void FMarginStructCustomization::OnValueCommitted( float NewValue, ETextCommit::Type CommitType, int32 PropertyIndex )
{
	TWeakPtr<IPropertyHandle> WeakHandlePtr = ChildPropertyHandles[ PropertyIndex ];
	WeakHandlePtr.Pin()->SetValue( NewValue );
}	
void FDestructibleMeshEditorViewportClient::ImportFBXChunks()
{
	// Get the FBX that we want to import
	TArray<FString> OpenFilenames;
	IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
	bool bOpened = false;
	if (DesktopPlatform != NULL)
	{
		bOpened = DesktopPlatform->OpenFileDialog(
			NULL, 
			NSLOCTEXT("UnrealEd", "ImportMatineeSequence", "Import UnrealMatinee Sequence").ToString(),
			*(FEditorDirectories::Get().GetLastDirectory(ELastDirectory::GENERIC_IMPORT)),
			TEXT(""),
			TEXT("FBX document|*.fbx"),
			EFileDialogFlags::None, 
			OpenFilenames);
	}

	if (bOpened)
	{
		// Get the filename from dialog
		FString ImportFilename = OpenFilenames[0];
		FString FileName = OpenFilenames[0];
		FEditorDirectories::Get().SetLastDirectory(ELastDirectory::GENERIC_IMPORT, FPaths::GetPath(FileName)); // Save path as default for next time.

		const FString FileExtension = FPaths::GetExtension(FileName);
		const bool bIsFBX = FCString::Stricmp(*FileExtension, TEXT("FBX")) == 0;

		if (bIsFBX)
		{
			FlushRenderingCommands();

			UnFbx::FFbxImporter* FFbxImporter = UnFbx::FFbxImporter::GetInstance();
			if (FFbxImporter->ImportFromFile( *ImportFilename, FPaths::GetExtension( ImportFilename ) ) )
			{
				TArray<FbxNode*> FbxMeshArray;
				FFbxImporter->FillFbxMeshArray(FFbxImporter->Scene->GetRootNode(), FbxMeshArray, FFbxImporter);

				UFbxStaticMeshImportData* ImportData = NewObject<UFbxStaticMeshImportData>(GetTransientPackage(), NAME_None, RF_NoFlags, NULL);

				TArray<UStaticMesh*> ChunkMeshes;

				for (int32 i=0; i < FbxMeshArray.Num(); ++i)
				{
					UStaticMesh* TempStaticMesh = NULL;
					TempStaticMesh = (UStaticMesh*)FFbxImporter->ImportStaticMesh(GetTransientPackage(), FbxMeshArray[i], NAME_None, RF_NoFlags, ImportData, 0);

					ChunkMeshes.Add(TempStaticMesh);
				}

				UDestructibleMesh* DestructibleMesh = DestructibleMeshEditorPtr.Pin()->GetDestructibleMesh();
				if (DestructibleMesh)
				{
					DestructibleMesh->SetupChunksFromStaticMeshes(ChunkMeshes);
				}
			}

			FFbxImporter->ReleaseScene();

			// Update the viewport
			DestructibleMeshEditorPtr.Pin()->RefreshTool();
			DestructibleMeshEditorPtr.Pin()->SetCurrentPreviewDepth(0xFFFFFFFF);	// This will get clamped to the max depth
		}
		else
		{
			// Invalid filename 
		}
	}
#if WITH_APEX
#endif // WITH_APEX
}
FText FActorInfoColumn::GetTextForItem( TWeakPtr<ITreeItem> TreeItem ) const
{
	auto Item = TreeItem.Pin();
	return Item.IsValid() ? FText::FromString(Item->Get(FGetInfo(CurrentMode))) : FText::GetEmpty();
}
			static void FillFileMenu( FMenuBuilder& MenuBuilder, TWeakPtr< FAssetEditorToolkit > AssetEditorToolkitWeak )
			{
				auto AssetEditorToolkit( AssetEditorToolkitWeak.Pin().ToSharedRef() );
				
				AssetEditorToolkit->FillDefaultFileMenuCommands( MenuBuilder );
			}
示例#5
0
/**
 * Perform an editor build with behavior dependent upon the specified id
 *
 * @param	Id	Action Id specifying what kind of build is requested
 *
 * @return	true if the build completed successfully; false if it did not (or was manually canceled)
 */
bool FEditorBuildUtils::EditorBuild( UWorld* InWorld, EBuildOptions::Type Id, const bool bAllowLightingDialog )
{
	FMessageLog("MapCheck").NewPage(LOCTEXT("MapCheckNewPage", "Map Check"));

	// Make sure to set this flag to false before ALL builds.
	GEditor->SetMapBuildCancelled( false );

	// Will be set to false if, for some reason, the build does not happen.
	bool bDoBuild = true;
	// Indicates whether the persistent level should be dirtied at the end of a build.
	bool bDirtyPersistentLevel = true;

	// Stop rendering thread so we're not wasting CPU cycles.
	StopRenderingThread();

	// Hack: These don't initialize properly and if you pick BuildAll right off the
	// bat when opening a map you will get incorrect values in them.
	GSwarmDebugOptions.Touch();

	// Show option dialog first, before showing the DlgBuildProgress window.
	FLightingBuildOptions LightingBuildOptions;
	if ( Id == EBuildOptions::BuildLighting )
	{
		// Retrieve settings from ini.
		GConfig->GetBool( TEXT("LightingBuildOptions"), TEXT("OnlyBuildSelected"),		LightingBuildOptions.bOnlyBuildSelected,			GEditorUserSettingsIni );
		GConfig->GetBool( TEXT("LightingBuildOptions"), TEXT("OnlyBuildCurrentLevel"),	LightingBuildOptions.bOnlyBuildCurrentLevel,		GEditorUserSettingsIni );
		GConfig->GetBool( TEXT("LightingBuildOptions"), TEXT("OnlyBuildSelectedLevels"),LightingBuildOptions.bOnlyBuildSelectedLevels,	GEditorUserSettingsIni );
		GConfig->GetBool( TEXT("LightingBuildOptions"), TEXT("OnlyBuildVisibility"),	LightingBuildOptions.bOnlyBuildVisibility,		GEditorUserSettingsIni );
		GConfig->GetBool( TEXT("LightingBuildOptions"), TEXT("UseErrorColoring"),		LightingBuildOptions.bUseErrorColoring,			GEditorUserSettingsIni );
		GConfig->GetBool( TEXT("LightingBuildOptions"), TEXT("ShowLightingBuildInfo"),	LightingBuildOptions.bShowLightingBuildInfo,		GEditorUserSettingsIni );
		int32 QualityLevel;
		GConfig->GetInt(  TEXT("LightingBuildOptions"), TEXT("QualityLevel"),			QualityLevel,						GEditorUserSettingsIni );
		QualityLevel = FMath::Clamp<int32>(QualityLevel, Quality_Preview, Quality_Production);
		LightingBuildOptions.QualityLevel = (ELightingBuildQuality)QualityLevel;
	}

	// Show the build progress dialog.
	SBuildProgressWidget::EBuildType BuildType = SBuildProgressWidget::BUILDTYPE_Geometry;

	switch (Id)
	{
	case EBuildOptions::BuildGeometry:
	case EBuildOptions::BuildVisibleGeometry:
	case EBuildOptions::BuildAll:
	case EBuildOptions::BuildAllOnlySelectedPaths:
		BuildType = SBuildProgressWidget::BUILDTYPE_Geometry;
		break;
	case EBuildOptions::BuildLighting:
		BuildType = SBuildProgressWidget::BUILDTYPE_Lighting;
		break;
	case EBuildOptions::BuildAIPaths:
	case EBuildOptions::BuildSelectedAIPaths:
		BuildType = SBuildProgressWidget::BUILDTYPE_Paths;
		break;
	case EBuildOptions::BuildHierarchicalLOD:
		BuildType = SBuildProgressWidget::BUILDTYPE_LODs;
		break;
	default:
		BuildType = SBuildProgressWidget::BUILDTYPE_Unknown;	
		break;
	}

	TWeakPtr<class SBuildProgressWidget> BuildProgressWidget = GWarn->ShowBuildProgressWindow();
	BuildProgressWidget.Pin()->SetBuildType(BuildType);

	bool bShouldMapCheck = true;
	switch( Id )
	{
	case EBuildOptions::BuildGeometry:
		{
			// We can't set the busy cursor for all windows, because lighting
			// needs a cursor for the lighting options dialog.
			const FScopedBusyCursor BusyCursor;

			GUnrealEd->Exec( InWorld, TEXT("MAP REBUILD") );

			TriggerNavigationBuilder(InWorld, Id);

			// No need to dirty the persient level if we're building BSP for a sub-level.
			bDirtyPersistentLevel = false;
			break;
		}
	case EBuildOptions::BuildVisibleGeometry:
		{
			// If any levels are hidden, prompt the user about how to proceed
			bDoBuild = GEditor->WarnAboutHiddenLevels( InWorld, true );
			if ( bDoBuild )
			{
				// We can't set the busy cursor for all windows, because lighting
				// needs a cursor for the lighting options dialog.
				const FScopedBusyCursor BusyCursor;

				GUnrealEd->Exec( InWorld, TEXT("MAP REBUILD ALLVISIBLE") );

				TriggerNavigationBuilder(InWorld, Id);
			}
			break;
		}

	case EBuildOptions::BuildLighting:
		{
			if( bDoBuild )
			{
				// We can't set the busy cursor for all windows, because lighting
				// needs a cursor for the lighting options dialog.
				const FScopedBusyCursor BusyCursor;
				GUnrealEd->BuildLighting( LightingBuildOptions );
				bShouldMapCheck = false;
			}
			break;
		}

	case EBuildOptions::BuildAIPaths:
		{
			bDoBuild = GEditor->WarnAboutHiddenLevels( InWorld, false );
			if ( bDoBuild )
			{
				GEditor->ResetTransaction( NSLOCTEXT("UnrealEd", "RebuildNavigation", "Rebuilding Navigation") );

				// We can't set the busy cursor for all windows, because lighting
				// needs a cursor for the lighting options dialog.
				const FScopedBusyCursor BusyCursor;

				TriggerNavigationBuilder(InWorld, Id);
			}

			break;
		}

	case EBuildOptions::BuildHierarchicalLOD:
		{
			bDoBuild = GEditor->WarnAboutHiddenLevels( InWorld, false );
			if ( bDoBuild )
			{
				GEditor->ResetTransaction( NSLOCTEXT("UnrealEd", "RebuildLOD", "Rebuilding HierarchicalLOD") );

				// We can't set the busy cursor for all windows, because lighting
				// needs a cursor for the lighting options dialog.
				const FScopedBusyCursor BusyCursor;

				TriggerHierarchicalLODBuilder(InWorld, Id);
			}

			break;
		}

	case EBuildOptions::BuildAll:
	case EBuildOptions::BuildAllSubmit:
		{
			bDoBuild = GEditor->WarnAboutHiddenLevels( InWorld, true );
			bool bLightingAlreadyRunning = GUnrealEd->WarnIfLightingBuildIsCurrentlyRunning();
			if ( bDoBuild && !bLightingAlreadyRunning )
			{
				// We can't set the busy cursor for all windows, because lighting
				// needs a cursor for the lighting options dialog.
				const FScopedBusyCursor BusyCursor;

				GUnrealEd->Exec( InWorld, TEXT("MAP REBUILD ALLVISIBLE") );

				// disable this in build all path, it's very slow, it can be painful
				// they don't have any collision, but make sure it's added first before doing anything
 				{
 					BuildProgressWidget.Pin()->SetBuildType(SBuildProgressWidget::BUILDTYPE_LODs);
 					TriggerHierarchicalLODBuilder(InWorld, Id);
 				}

				{
					BuildProgressWidget.Pin()->SetBuildType(SBuildProgressWidget::BUILDTYPE_Paths);
					TriggerNavigationBuilder(InWorld, Id);
				}

				//Do a canceled check before moving on to the next step of the build.
				if( GEditor->GetMapBuildCancelled() )
				{
					break;
				}
				else
				{
					BuildProgressWidget.Pin()->SetBuildType(SBuildProgressWidget::BUILDTYPE_Lighting);

					FLightingBuildOptions LightingOptions;

					int32 QualityLevel;

					// Force automated builds to always use production lighting
					if ( Id == EBuildOptions::BuildAllSubmit )
					{
						QualityLevel = Quality_Production;
					}
					else
					{
						GConfig->GetInt( TEXT("LightingBuildOptions"), TEXT("QualityLevel"), QualityLevel, GEditorUserSettingsIni);
						QualityLevel = FMath::Clamp<int32>(QualityLevel, Quality_Preview, Quality_Production);
					}
					LightingOptions.QualityLevel = (ELightingBuildQuality)QualityLevel;

					GUnrealEd->BuildLighting(LightingOptions);
					bShouldMapCheck = false;
				}
			}
			break;
		}

	default:
		UE_LOG(LogEditorBuildUtils, Warning, TEXT("Invalid build Id"));
		break;
	}

	// Check map for errors (only if build operation happened)
	if ( bShouldMapCheck && bDoBuild && !GEditor->GetMapBuildCancelled() )
	{
		GUnrealEd->Exec( InWorld, TEXT("MAP CHECK DONTDISPLAYDIALOG") );
	}

	// Re-start the rendering thread after build operations completed.
	if (GUseThreadedRendering)
	{
		StartRenderingThread();
	}

	if ( bDoBuild && InWorld->Scene )
	{
		// Invalidating lighting marked various components as needing a re-register
		// Propagate the re-registers before rendering the scene to get the latest state
		InWorld->SendAllEndOfFrameUpdates();
	}

	if ( bDoBuild )
	{
		// Display elapsed build time.
		UE_LOG(LogEditorBuildUtils, Log,  TEXT("Build time %s"), *BuildProgressWidget.Pin()->BuildElapsedTimeText().ToString() );
	}

	// Build completed, hide the build progress dialog.
	// NOTE: It's important to turn off modalness before hiding the window, otherwise a background
	//		 application may unexpectedly be promoted to the foreground, obscuring the editor.
	GWarn->CloseBuildProgressWindow();
	
	GUnrealEd->RedrawLevelEditingViewports();

	if ( bDoBuild )
	{
		if ( bDirtyPersistentLevel )
		{
			InWorld->MarkPackageDirty();
		}
		ULevel::LevelDirtiedEvent.Broadcast();
	}

	// Don't show map check if we cancelled build because it may have some bogus data
	const bool bBuildCompleted = bDoBuild && !GEditor->GetMapBuildCancelled();
	if( bBuildCompleted )
	{
		if (bShouldMapCheck)
		{
			FMessageLog("MapCheck").Open( EMessageSeverity::Warning );
		}
		FMessageLog("LightingResults").Notify(LOCTEXT("LightingErrorsNotification", "There were lighting errors."), EMessageSeverity::Error);
	}

	return bBuildCompleted;
}
void FMaterialEditorViewportClient::Draw(FViewport* InViewport,FCanvas* Canvas)
{
	FEditorViewportClient::Draw(InViewport, Canvas);
	MaterialEditorPtr.Pin()->DrawMessages(InViewport, Canvas);
}
	/**
	 * Construct this widget.  Called by the SNew() Slate macro.
	 *
	 * @param	InArgs				Declaration used by the SNew() macro to construct this widget
	 * @param	Factory				The factory this menu entry represents
	 */
	void Construct( const FArguments& InArgs, UFactory* Factory )
	{
		const FName ClassThumbnailBrushOverride = Factory->GetNewAssetThumbnailOverride();
		const FSlateBrush* ClassThumbnail = nullptr;
		if (ClassThumbnailBrushOverride.IsNone())
		{
			ClassThumbnail = FClassIconFinder::FindThumbnailForClass(Factory->GetSupportedClass());
		}
		else
		{
			// Instead of getting the override thumbnail directly from the editor style here get it from the
			// ClassIconFinder since it may have additional styles registered which can be searched by passing
			// it as a default with no class to search for.
			ClassThumbnail = FClassIconFinder::FindThumbnailForClass(nullptr, ClassThumbnailBrushOverride);
		}

		FAssetToolsModule& AssetToolsModule = FAssetToolsModule::GetModule();
		TWeakPtr<IAssetTypeActions> AssetTypeActions = AssetToolsModule.Get().GetAssetTypeActionsForClass(Factory->GetSupportedClass());

		FLinearColor AssetColor = FLinearColor::White;
		if ( AssetTypeActions.IsValid() )
		{
			AssetColor = AssetTypeActions.Pin()->GetTypeColor();
		}

		ChildSlot
		[
			SNew( SHorizontalBox )
			+SHorizontalBox::Slot()
			.Padding( 4, 0, 0, 0 )
			.VAlign(VAlign_Center)
			.AutoWidth()
			[
				SNew( SOverlay )

				+SOverlay::Slot()
				[
					SNew( SBox )
					.WidthOverride( InArgs._Width + 4 )
					.HeightOverride( InArgs._Height + 4 )
					[
						SNew( SBorder )
						.BorderImage( FEditorStyle::GetBrush("AssetThumbnail.AssetBackground") )
						.BorderBackgroundColor(AssetColor.CopyWithNewOpacity(0.3f))
						.Padding( 2.0f )
						.VAlign( VAlign_Center )
						.HAlign( HAlign_Center )
						[
							SNew( SImage )
							.Image( ClassThumbnail )
						]
					]
				]

				+SOverlay::Slot()
				.HAlign(HAlign_Fill)
				.VAlign(VAlign_Bottom)
				[
					SNew( SBorder )
					.BorderImage( FEditorStyle::GetBrush("WhiteBrush") )
					.BorderBackgroundColor( AssetColor )
					.Padding( FMargin(0, FMath::Max(FMath::CeilToFloat(InArgs._Width*0.025f), 3.0f), 0, 0) )
				]
			]

			+SHorizontalBox::Slot()
			.VAlign(VAlign_Center)
			.Padding(4, 0, 4, 0)
			[
				SNew( SVerticalBox )
				+SVerticalBox::Slot()
				.Padding(0, 0, 0, 1)
				.AutoHeight()
				[
					SNew(STextBlock)
					.Font( FEditorStyle::GetFontStyle("LevelViewportContextMenu.AssetLabel.Text.Font") )
					.Text( Factory->GetDisplayName() )
				]
			]
		];

		
		SetToolTip(IDocumentation::Get()->CreateToolTip(Factory->GetToolTip(), nullptr, Factory->GetToolTipDocumentationPage(), Factory->GetToolTipDocumentationExcerpt()));
	}
示例#8
0
bool FAssetEditorManager::OpenEditorForAssets( const TArray< UObject* >& Assets, const EToolkitMode::Type ToolkitMode, TSharedPtr< IToolkitHost > OpenedFromLevelEditor )
{
	if( Assets.Num() == 1 )
	{
		return OpenEditorForAsset(Assets[0], ToolkitMode, OpenedFromLevelEditor);
	}
	else if (Assets.Num() > 0)
	{
		// If any of the assets are already open, remove them from the list of assets to open an editor for
		TArray<UObject*> AlreadyOpenAssets;
		for (auto Asset : Assets)
		{
			if( FindEditorForAsset(Asset, true) != nullptr )
			{
				AlreadyOpenAssets.Add(Asset);
			}
		}

		// Verify that all the assets are of the same class
		bool bAssetClassesMatch = true;
		auto AssetClass = Assets[0]->GetClass();
		for (int32 i = 1; i < Assets.Num(); i++)
		{
			if (Assets[i]->GetClass() != AssetClass)
			{
				bAssetClassesMatch = false;
				break;
			}
		}

		// If the classes don't match or any of the selected assets are already open, just open each asset in its own editor.
		if (bAssetClassesMatch && AlreadyOpenAssets.Num() == 0)
		{
			FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
			TWeakPtr<IAssetTypeActions> AssetTypeActions = AssetToolsModule.Get().GetAssetTypeActionsForClass(AssetClass);

			if (AssetTypeActions.IsValid())
			{
				GWarn->BeginSlowTask(LOCTEXT("OpenEditor", "Opening Editor(s)..."), true);

				// Determine the appropriate toolkit mode for the asset type
				auto ActualToolkitMode = ToolkitMode;
				if (AssetTypeActions.Pin()->ShouldForceWorldCentric())
				{
					// This asset type prefers a specific toolkit mode
					ActualToolkitMode = EToolkitMode::WorldCentric;

					if (!OpenedFromLevelEditor.IsValid())
					{
						// We don't have a level editor to spawn in world-centric mode, so we'll find one now
						// @todo sequencer: We should eventually eliminate this code (incl include dependencies) or change it to not make assumptions about a single level editor
						OpenedFromLevelEditor = FModuleManager::LoadModuleChecked< FLevelEditorModule >("LevelEditor").GetFirstLevelEditor();
					}
				}

				if (ActualToolkitMode != EToolkitMode::WorldCentric && OpenedFromLevelEditor.IsValid())
				{
					// @todo toolkit minor: Kind of lame use of a static variable here to prime the new asset editor.  This was done to avoid refactoring a few dozen files for a very minor change.
					FAssetEditorToolkit::SetPreviousWorldCentricToolkitHostForNewAssetEditor(OpenedFromLevelEditor.ToSharedRef());
				}

				// Some assets (like UWorlds) may be destroyed and recreated as part of opening. To protect against this, keep the path to each asset and try to re-find any if they disappear.
				struct FLocalAssetInfo
				{
					TWeakObjectPtr<UObject> WeakAsset;
					FString AssetPath;

					FLocalAssetInfo(const TWeakObjectPtr<UObject>& InWeakAsset, const FString& InAssetPath)
						: WeakAsset(InWeakAsset), AssetPath(InAssetPath) {}
				};

				TArray<FLocalAssetInfo> AssetInfoList;
				AssetInfoList.Reserve(Assets.Num());
				for (auto Asset : Assets)
				{
					AssetInfoList.Add(FLocalAssetInfo(Asset, Asset->GetPathName()));
				}

				// How to handle multiple assets is left up to the type actions (i.e. open a single shared editor or an editor for each)
				AssetTypeActions.Pin()->OpenAssetEditor(Assets, ActualToolkitMode == EToolkitMode::WorldCentric ? OpenedFromLevelEditor : TSharedPtr<IToolkitHost>());

				// If any assets were destroyed, attempt to find them if they were recreated
				for (int32 i = 0; i < Assets.Num(); i++)
				{
					auto& AssetInfo = AssetInfoList[i];
					auto Asset = Assets[i];

					if (!AssetInfo.WeakAsset.IsValid() && !AssetInfo.AssetPath.IsEmpty())
					{
						Asset = FindObject<UObject>(nullptr, *AssetInfo.AssetPath);
					}
				}

				//@todo if needed, broadcast the event for every asset. It is possible, however, that a single shared editor was opened by the AssetTypeActions, not an editor for each asset.
				/*AssetEditorOpenedEvent.Broadcast(Asset);*/

				GWarn->EndSlowTask();
			}
		}
		else
		{
			// Asset types don't match or some are already open, so just open individual editors for the unopened ones
			for (auto Asset : Assets)
			{
				if (!AlreadyOpenAssets.Contains(Asset))
				{
					OpenEditorForAsset(Asset, ToolkitMode, OpenedFromLevelEditor);
				}
			}
		}
	}

	return true;
}
示例#9
0
FReply STimelineLabelAnchor::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
	if (MouseEvent.GetEffectingButton() == EKeys::RightMouseButton && TimelineOwner.IsValid() && TimelineOwner.Pin()->IsSelected())
	{
		SetIsOpen(!IsOpen());
		return FReply::Handled();
	}
	return FReply::Unhandled();
}
TSharedRef< SWidget > FLevelEditorToolBar::GenerateMatineeMenuContent( TSharedRef<FUICommandList> InCommandList, TWeakPtr<SLevelEditor> LevelEditorWeakPtr )
{
#define LOCTEXT_NAMESPACE "LevelToolBarMatineeMenu"

	const bool bShouldCloseWindowAfterMenuSelection = true;
	FMenuBuilder MenuBuilder( bShouldCloseWindowAfterMenuSelection, InCommandList );

	// We can't build a list of Matinees while the current World is a PIE world.
	FSceneOutlinerInitializationOptions InitOptions;
	{
		InitOptions.Mode = ESceneOutlinerMode::ActorPicker;

		// We hide the header row to keep the UI compact.
		// @todo: Might be useful to have this sometimes, actually.  Ideally the user could summon it.
		InitOptions.bShowHeaderRow = false;

		// Only display Matinee actors
		InitOptions.ActorFilters = MakeShareable( new TFilterCollection< const AActor* const >() );

		struct Local
		{
			static bool IsMatineeActor( const AActor* const Actor )
			{
				return Actor->IsA( AMatineeActor::StaticClass() );
			}
		};

		InitOptions.ActorFilters->Add( MakeShareable( new TDelegateFilter< const AActor* const >( TDelegateFilter< const AActor* const >::FPredicate::CreateStatic( &Local::IsMatineeActor ) ) ) );
	}

	// actor selector to allow the user to choose a Matinee actor
	FSceneOutlinerModule& SceneOutlinerModule = FModuleManager::LoadModuleChecked<FSceneOutlinerModule>( "SceneOutliner" );
	TSharedRef< SWidget > MiniSceneOutliner =
		SNew( SVerticalBox )
		+SVerticalBox::Slot()
		.AutoHeight()
		.MaxHeight(400.0f)
		[
			SceneOutlinerModule.CreateSceneOutliner(
				InitOptions,
				FOnContextMenuOpening(), //no context menu allowed here
				FOnActorPicked::CreateStatic( &FLevelEditorToolBar::OnMatineeActorPicked ) )
		];

	// Give the scene outliner a border and background
	const FSlateBrush* BackgroundBrush = FEditorStyle::GetBrush( "Menu.Background" );
	TSharedRef< SBorder > RootBorder =
		SNew( SBorder )
		.Padding(3)
		.BorderImage( BackgroundBrush )
		.ForegroundColor( FEditorStyle::GetSlateColor("DefaultForeground") )

		// Assign the box panel as the child
		[
			SNew( SVerticalBox )
			+SVerticalBox::Slot()
			.AutoHeight()
			.Padding( 5 )
			.HAlign( HAlign_Center )
			[
				SNew( STextBlock )
				.Text( LOCTEXT( "SelectMatineeActorToEdit", "Select a Matinee actor" ) )
			]

			+SVerticalBox::Slot()
				.AutoHeight()
				.Padding( 2 )
				[
					MiniSceneOutliner
				]
		]
	;

	MenuBuilder.BeginSection("LevelEditorNewMatinee", LOCTEXT("MatineeMenuCombo_NewHeading", "New"));
	{
		MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().AddMatinee );
	}
	MenuBuilder.EndSection();

	bool bHasAnyMatineeActors = false;
	TActorIterator<AMatineeActor> MatineeIt( LevelEditorWeakPtr.Pin()->GetWorld() );

	bHasAnyMatineeActors = MatineeIt;

	//Add a heading to separate the existing matinees from the 'Add New Matinee Actor' button
	MenuBuilder.BeginSection("LevelEditorExistingMatinee", LOCTEXT( "MatineeMenuCombo_ExistingHeading", "Edit Existing Matinee" ) );
	{
		if( bHasAnyMatineeActors )
		{
			MenuBuilder.AddWidget(MiniSceneOutliner, FText::GetEmpty(), false);
		}
	}
	MenuBuilder.EndSection();
#undef LOCTEXT_NAMESPACE

	return MenuBuilder.MakeWidget();
}
示例#11
0
bool FAssetEditorManager::OpenEditorForAsset(UObject* Asset, const EToolkitMode::Type ToolkitMode, TSharedPtr< IToolkitHost > OpenedFromLevelEditor )
{
	check(Asset);
	// @todo toolkit minor: When "Edit Here" happens in a different level editor from the one that an asset is already
	//    being edited within, we should decide whether to disallow "Edit Here" in that case, or to close the old asset
	//    editor and summon it in the new level editor, or to just foreground the old level editor (current behavior)

	const bool bBringToFrontIfOpen = true;

	// Don't open asset editors for cooked packages
	if (UPackage* Package = Asset->GetOutermost())
	{
		if (Package->bIsCookedForEditor)
		{
			return false;
		}
	}
	
	AssetEditorRequestOpenEvent.Broadcast(Asset);

	if( FindEditorForAsset(Asset, bBringToFrontIfOpen) != nullptr )
	{
		// This asset is already open in an editor! (the call to FindEditorForAsset above will bring it to the front)
		return true;
	}
	else
	{
		GWarn->BeginSlowTask( LOCTEXT("OpenEditor", "Opening Editor..."), true);
	}


	FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));

	TWeakPtr<IAssetTypeActions> AssetTypeActions = AssetToolsModule.Get().GetAssetTypeActionsForClass( Asset->GetClass() );
	
	auto ActualToolkitMode = ToolkitMode;
	if( AssetTypeActions.IsValid() )
	{
		if( AssetTypeActions.Pin()->ShouldForceWorldCentric() )
		{
			// This asset type prefers a specific toolkit mode
			ActualToolkitMode = EToolkitMode::WorldCentric;

			if( !OpenedFromLevelEditor.IsValid() )
			{
				// We don't have a level editor to spawn in world-centric mode, so we'll find one now
				// @todo sequencer: We should eventually eliminate this code (incl include dependencies) or change it to not make assumptions about a single level editor
				OpenedFromLevelEditor = FModuleManager::LoadModuleChecked< FLevelEditorModule >( "LevelEditor" ).GetFirstLevelEditor();
			}
		}
	}
	
	if( ActualToolkitMode != EToolkitMode::WorldCentric && OpenedFromLevelEditor.IsValid() )
	{
		// @todo toolkit minor: Kind of lame use of a static variable here to prime the new asset editor.  This was done to avoid refactoring a few dozen files for a very minor change.
		FAssetEditorToolkit::SetPreviousWorldCentricToolkitHostForNewAssetEditor( OpenedFromLevelEditor.ToSharedRef() );
	}

	// Disallow opening an asset editor for classes
	bool bCanSummonSimpleAssetEditor = !Asset->IsA<UClass>();

	if( AssetTypeActions.IsValid() )
	{
		TArray<UObject*> AssetsToEdit;
		AssetsToEdit.Add(Asset);

		// Some assets (like UWorlds) may be destroyed and recreated as part of opening. To protect against this, keep the path to the asset and try to re-find it if it disappeared.
		TWeakObjectPtr<UObject> WeakAsset = Asset;
		const FString AssetPath = Asset->GetPathName();

		AssetTypeActions.Pin()->OpenAssetEditor(AssetsToEdit, ActualToolkitMode == EToolkitMode::WorldCentric ? OpenedFromLevelEditor : TSharedPtr<IToolkitHost>());
		
		// If the Asset was destroyed, attempt to find it if it was recreated
		if ( !WeakAsset.IsValid() && !AssetPath.IsEmpty() )
		{
			Asset = FindObject<UObject>(nullptr, *AssetPath);
		}

		AssetEditorOpenedEvent.Broadcast(Asset);
	}
	else if( bCanSummonSimpleAssetEditor )
	{
		// No asset type actions for this asset. Just use a properties editor.
		FSimpleAssetEditor::CreateEditor(ActualToolkitMode, ActualToolkitMode == EToolkitMode::WorldCentric ? OpenedFromLevelEditor : TSharedPtr<IToolkitHost>(), Asset);
	}

	GWarn->EndSlowTask();
	return true;
}
FText FLevelEditorToolBar::GetOpenGameModeBlueprintLabel(TWeakPtr< SLevelEditor > InLevelEditor)
{
#define LOCTEXT_NAMESPACE "LevelToolBarViewMenu"
	if(IsValidGameModeBlueprint(InLevelEditor))
	{
		return FText::Format( LOCTEXT("GameModeEditBlueprint", "GameMode: Edit {GameModeName}"), FText::FromString(InLevelEditor.Pin()->GetWorld()->GetWorldSettings()->DefaultGameMode->ClassGeneratedBy->GetName()));
	}

	return LOCTEXT("GameModeCreateBlueprint", "GameMode: Create...");
#undef LOCTEXT_NAMESPACE
}
bool FLevelEditorToolBar::IsValidGameModeBlueprint(TWeakPtr< SLevelEditor > InLevelEditor)
{
	AWorldSettings* WorldSettings = InLevelEditor.Pin()->GetWorld()->GetWorldSettings();
	return WorldSettings->DefaultGameMode && WorldSettings->DefaultGameMode->ClassGeneratedBy;
}
TSharedRef< SWidget > FLevelEditorToolBar::GenerateOpenBlueprintMenuContent( TSharedRef<FUICommandList> InCommandList, TWeakPtr< SLevelEditor > InLevelEditor )
{
#define LOCTEXT_NAMESPACE "LevelToolBarViewMenu"

	struct FBlueprintMenus
	{
		/** Generates a sub-level Blueprints sub-menu */
		static void MakeSubLevelsMenu(FMenuBuilder& InMenuBuilder, TWeakPtr< SLevelEditor > InLvlEditor)
		{
			FSlateIcon EditBP(FEditorStyle::Get().GetStyleSetName(), TEXT("LevelEditor.OpenLevelBlueprint"));

			InMenuBuilder.BeginSection(NAME_None, LOCTEXT("SubLevelsHeading", "Sub-Level Blueprints"));
			{
				UWorld* World = InLvlEditor.Pin()->GetWorld();
				for (int32 iLevel = 0; iLevel < World->GetNumLevels(); iLevel++)
				{
					ULevel* Level = World->GetLevel(iLevel);
					if (Level != NULL && Level->GetOutermost() != NULL)
					{
						if (!Level->IsPersistentLevel())
						{
							FUIAction UIAction
								(
								FExecuteAction::CreateStatic(&FLevelEditorToolBar::OnOpenSubLevelBlueprint, Level)
								);

							FText DisplayName = FText::Format(LOCTEXT("SubLevelBlueprintItem", "Edit {LevelName}"), FText::FromString(FPaths::GetCleanFilename(Level->GetOutermost()->GetName())));
							InMenuBuilder.AddMenuEntry(DisplayName, FText::GetEmpty(), EditBP, UIAction);
						}
					}
				}
			}
			InMenuBuilder.EndSection();
		}

		/** Handle BP being selected from popup picker */
		static void OnBPSelected(const class FAssetData& AssetData)
		{
			UBlueprint* SelectedBP = Cast<UBlueprint>(AssetData.GetAsset());
			if(SelectedBP)
			{
				FAssetEditorManager::Get().OpenEditorForAsset(SelectedBP);
			}
		}


		/** Generates 'eopn blueprint' sub-menu */
		static void MakeOpenClassBPMenu(FMenuBuilder& InMenuBuilder)
		{
			FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked<FContentBrowserModule>(TEXT("ContentBrowser"));

			// Configure filter for asset picker
			FAssetPickerConfig Config;
			Config.Filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName());
			Config.InitialAssetViewType = EAssetViewType::List;
			Config.ThumbnailScale = 0; // make thumbnails as small as possible
			Config.OnAssetSelected = FOnAssetSelected::CreateStatic(&FBlueprintMenus::OnBPSelected);
			Config.bAllowDragging = false;
			// Don't show stuff in Engine
			Config.Filter.PackagePaths.Add("/Game");
			Config.Filter.bRecursivePaths = true;

			TSharedRef<SWidget> Widget = 
				SNew(SBox)
				.WidthOverride(300.f)
				.HeightOverride(300.f)
				[
					ContentBrowserModule.Get().CreateAssetPicker(Config)
				];
		

			InMenuBuilder.BeginSection(NAME_None, LOCTEXT("BrowseHeader", "Browse"));
			{
				InMenuBuilder.AddWidget(Widget, FText::GetEmpty());
			}
			InMenuBuilder.EndSection();
		}
	};


	const bool bShouldCloseWindowAfterMenuSelection = true;
	FMenuBuilder MenuBuilder( bShouldCloseWindowAfterMenuSelection, InCommandList );

	MenuBuilder.BeginSection(NAME_None, LOCTEXT("LevelScriptBlueprints", "Level Blueprints"));
	{
		MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().OpenLevelBlueprint );

		// If there are any sub-levels, display the sub-menu. A single level means there is only the persistent level
		UWorld* World = InLevelEditor.Pin()->GetWorld();
		if(World->GetNumLevels() > 1)
		{
			MenuBuilder.AddSubMenu(
				LOCTEXT( "SubLevelsSubMenu", "Sub-Levels" ),
				LOCTEXT( "SubLevelsSubMenu_ToolTip", "Shows available sub-level Blueprints that can be edited." ),
				FNewMenuDelegate::CreateStatic( &FBlueprintMenus::MakeSubLevelsMenu, InLevelEditor ), 
				FUIAction(), NAME_None, EUserInterfaceActionType::Button, false, FSlateIcon(FEditorStyle::Get().GetStyleSetName(), TEXT("LevelEditor.OpenLevelBlueprint")) );
		}
	}
	MenuBuilder.EndSection();

	MenuBuilder.BeginSection(NAME_None, LOCTEXT("GameBlueprints", "Game Blueprints"));
	{
		FSlateIcon EditBPIcon(FEditorStyle::Get().GetStyleSetName(), TEXT("PropertyWindow.Button_Edit"));
		FSlateIcon NewBPIcon(FEditorStyle::Get().GetStyleSetName(), TEXT("PropertyWindow.Button_AddToArray"));

		// Game Mode
		TAttribute<FText>::FGetter DynamicGameModeGetter;
		DynamicGameModeGetter.BindStatic(&FLevelEditorToolBar::GetOpenGameModeBlueprintLabel, InLevelEditor);
		TAttribute<FText> DynamicGameModeLabel = TAttribute<FText>::Create(DynamicGameModeGetter);

		TAttribute<FText>::FGetter DynamicGameModeGetter_Tooltip;
		DynamicGameModeGetter_Tooltip.BindStatic(&FLevelEditorToolBar::GetOpenGameModeBlueprintTooltip, InLevelEditor);
		TAttribute<FText> DynamicGameModeTooltip = TAttribute<FText>::Create(DynamicGameModeGetter_Tooltip);
		MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().OpenGameModeBlueprint, NAME_None, DynamicGameModeLabel, DynamicGameModeTooltip, IsValidGameModeBlueprint(InLevelEditor)? EditBPIcon : NewBPIcon );

		// Game State
		TAttribute<FText>::FGetter DynamicGameStateGetter;
		DynamicGameStateGetter.BindStatic(&FLevelEditorToolBar::GetOpenGameStateBlueprintLabel, InLevelEditor);
		TAttribute<FText> DynamicGameStateLabel = TAttribute<FText>::Create(DynamicGameStateGetter);

		TAttribute<FText>::FGetter DynamicGameStateGetter_Tooltip;
		DynamicGameStateGetter_Tooltip.BindStatic(&FLevelEditorToolBar::GetOpenGameStateBlueprintTooltip, InLevelEditor);
		TAttribute<FText> DynamicGameStateTooltip = TAttribute<FText>::Create(DynamicGameStateGetter_Tooltip);
		MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().OpenGameStateBlueprint, NAME_None, DynamicGameStateLabel, DynamicGameStateTooltip, IsValidGameStateBlueprint(InLevelEditor)? EditBPIcon : NewBPIcon );

		// Pawn
		TAttribute<FText>::FGetter DynamicDefaultPawnGetter;
		DynamicDefaultPawnGetter.BindStatic(&FLevelEditorToolBar::GetOpenPawnBlueprintLabel, InLevelEditor);
		TAttribute<FText> DynamicDefaultPawnLabel = TAttribute<FText>::Create(DynamicDefaultPawnGetter);

		TAttribute<FText>::FGetter DynamicDefaultPawnGetter_Tooltip;
		DynamicDefaultPawnGetter_Tooltip.BindStatic(&FLevelEditorToolBar::GetOpenPawnBlueprintTooltip, InLevelEditor);
		TAttribute<FText> DynamicDefaultPawnTooltip = TAttribute<FText>::Create(DynamicDefaultPawnGetter_Tooltip);
		MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().OpenDefaultPawnBlueprint, NAME_None, DynamicDefaultPawnLabel, DynamicDefaultPawnTooltip, IsValidPawnBlueprint(InLevelEditor)? EditBPIcon : NewBPIcon );

		// HUD
		TAttribute<FText>::FGetter DynamicHUDGetter;
		DynamicHUDGetter.BindStatic(&FLevelEditorToolBar::GetOpenHUDBlueprintLabel, InLevelEditor);
		TAttribute<FText> DynamicHUDLabel = TAttribute<FText>::Create(DynamicHUDGetter);

		TAttribute<FText>::FGetter DynamicHUDGetter_Tooltip;
		DynamicHUDGetter_Tooltip.BindStatic(&FLevelEditorToolBar::GetOpenHUDBlueprintTooltip, InLevelEditor);
		TAttribute<FText> DynamicHUDTooltip = TAttribute<FText>::Create(DynamicHUDGetter_Tooltip);
		MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().OpenHUDBlueprint, NAME_None, DynamicHUDLabel, DynamicHUDTooltip, IsValidHUDBlueprint(InLevelEditor)? EditBPIcon : NewBPIcon );

		// Player Controller
		TAttribute<FText>::FGetter DynamicPlayerControllerGetter;
		DynamicPlayerControllerGetter.BindStatic(&FLevelEditorToolBar::GetOpenPlayerControllerBlueprintLabel, InLevelEditor);
		TAttribute<FText> DynamicPlayerControllerLabel = TAttribute<FText>::Create(DynamicPlayerControllerGetter);

		TAttribute<FText>::FGetter DynamicPlayerControllerGetter_Tooltip;
		DynamicPlayerControllerGetter_Tooltip.BindStatic(&FLevelEditorToolBar::GetOpenPlayerControllerBlueprintTooltip, InLevelEditor);
		TAttribute<FText> DynamicPlayerControllerTooltip = TAttribute<FText>::Create(DynamicPlayerControllerGetter_Tooltip);
		MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().OpenPlayerControllerBlueprint, NAME_None, DynamicPlayerControllerLabel, DynamicPlayerControllerTooltip, IsValidPlayerControllerBlueprint(InLevelEditor)? EditBPIcon : NewBPIcon );
	}
	MenuBuilder.EndSection();

	MenuBuilder.BeginSection(NAME_None, LOCTEXT("ClassBlueprints", "Class Blueprints"));
	{
		// New Class Blueprint...
		MenuBuilder.AddMenuEntry(FLevelEditorCommands::Get().CreateClassBlueprint, NAME_None, LOCTEXT("NewClassBlueprint", "New Class Blueprint..."));

		// Open Class Blueprint...
		FSlateIcon OpenBPIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.OpenClassBlueprint");
		MenuBuilder.AddSubMenu(
			LOCTEXT("OpenClassBlueprintSubMenu", "Open Class Blueprint..."),
			LOCTEXT("OpenClassBlueprintSubMenu_ToolTip", "Open an existing Class Blueprint in this project"),
			FNewMenuDelegate::CreateStatic(&FBlueprintMenus::MakeOpenClassBPMenu), 
			false, 
			OpenBPIcon );
	}
	MenuBuilder.EndSection();

#undef LOCTEXT_NAMESPACE

	return MenuBuilder.MakeWidget();
}
FReply SVisualLoggerTimelinesContainer::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent)
{
	if (InKeyEvent.GetKey() == EKeys::A && InKeyEvent.IsLeftControlDown())
	{
		for (TSharedPtr<SLogVisualizerTimeline>& Timeline : TimelineItems)
		{
			SetSelectionState(Timeline, true, false);
		}

		return FReply::Handled();
	}
	else if (InKeyEvent.GetKey() == EKeys::Platform_Delete && CachedSelectedTimelines.Num() > 0)
	{
		TWeakPtr<SLogVisualizerTimeline>  NotSelectedOne;
		for (TSharedPtr<SLogVisualizerTimeline>& CurrentNode : CachedSelectedTimelines)
		{
			TSharedPtr<SLogVisualizerTimeline> LastSelected = CachedSelectedTimelines[CachedSelectedTimelines.Num() - 1];
			bool bFoundSelectedOne = false;

			for (TSharedPtr<SLogVisualizerTimeline>& Timeline : TimelineItems)
			{
				if (IsNodeSelected(Timeline) == false)
				{
					NotSelectedOne = Timeline;
				}
				if (LastSelected == Timeline)
				{
					if (bFoundSelectedOne && NotSelectedOne.IsValid())
					{
						break;
					}
					bFoundSelectedOne = true;
				}
			}
			FVisualLoggerDatabase::Get().RemoveRow(CurrentNode->GetName());
			TimelineItems.Remove(CurrentNode);
			ContainingBorder->RemoveSlot(CurrentNode.ToSharedRef());
		}

		if (NotSelectedOne.IsValid())
		{
			SetSelectionState(NotSelectedOne.Pin(), true, true);
		}

		return FReply::Handled();
	}
	else if (InKeyEvent.GetKey() == EKeys::Up || InKeyEvent.GetKey() == EKeys::Down)
	{
		TSharedPtr<SLogVisualizerTimeline> PreviousTimeline;
		TSharedPtr<SLogVisualizerTimeline> LastSelected = CachedSelectedTimelines[CachedSelectedTimelines.Num() - 1];
		for (int32 Index = 0; Index < TimelineItems.Num(); ++Index)
		{
			auto& CurrentItem = TimelineItems[Index];
			if (LastSelected == CurrentItem)
			{
				if (InKeyEvent.GetKey() == EKeys::Up && PreviousTimeline.IsValid())
				{
					SetSelectionState(PreviousTimeline, true, true);
				}
				else if (InKeyEvent.GetKey() == EKeys::Down)
				{
					// let's find next visible time line
					if (TimelineItems.IsValidIndex(Index + 1))
					{
						for (int32 i = Index + 1; i < TimelineItems.Num(); ++i)
						{
							if (TimelineItems[i]->GetVisibility() == EVisibility::Visible)
							{
								SetSelectionState(TimelineItems[i], true, true);
								break;
							}
						}
					}
				}
				break;
			}

			if (CurrentItem->GetVisibility() == EVisibility::Visible)
			{
				PreviousTimeline = CurrentItem;
			}
		}
		return FReply::Handled();
	}

	return FReply::Unhandled();
}
void FMathStructCustomization::OnValueCommitted( NumericType NewValue, ETextCommit::Type CommitType, TWeakPtr<IPropertyHandle> WeakHandlePtr )
{
	WeakHandlePtr.Pin()->SetValue( NewValue );
}	
/**
 * Builds this MultiBlock widget up from the MultiBlock associated with it
 */
void SToolBarButtonBlock::BuildMultiBlockWidget(const ISlateStyle* StyleSet, const FName& StyleName)
{
	struct Local
	{
		/** Appends the key binding to the end of the provided ToolTip */
		static FText AppendKeyBindingToToolTip( const TAttribute<FText> ToolTip, TWeakPtr< const FUICommandInfo> Command )
		{
			TSharedPtr<const FUICommandInfo> CommandPtr = Command.Pin();

			if( CommandPtr.IsValid() && CommandPtr->GetActiveChord()->IsValidChord() )
			{
				FFormatNamedArguments Args;
				Args.Add( TEXT("ToolTipDescription"), ToolTip.Get() );
				Args.Add( TEXT("Keybinding"), CommandPtr->GetInputText() );
				return FText::Format( NSLOCTEXT("ToolBar", "ToolTip + Keybinding", "{ToolTipDescription} ({Keybinding})"), Args );
			}
			else
			{
				return ToolTip.Get();
			}
		}
	};


	TSharedRef< const FMultiBox > MultiBox( OwnerMultiBoxWidget.Pin()->GetMultiBox() );
	
	TSharedRef< const FToolBarButtonBlock > ToolBarButtonBlock = StaticCastSharedRef< const FToolBarButtonBlock >( MultiBlock.ToSharedRef() );

	// Allow the block to override the action's label and tool tip string, if desired
	TAttribute<FText> ActualLabel;
	if (ToolBarButtonBlock->LabelOverride.IsSet())
	{
		ActualLabel = ToolBarButtonBlock->LabelOverride;
	}
	else
	{
		ActualLabel = ToolBarButtonBlock->GetAction()->GetLabel();
	}

	// Add this widget to the search list of the multibox
	if (MultiBlock->GetSearchable())
		OwnerMultiBoxWidget.Pin()->AddSearchElement(this->AsWidget(), ActualLabel.Get());

	TAttribute<FText> ActualToolTip;
	if (ToolBarButtonBlock->ToolTipOverride.IsSet())
	{
		ActualToolTip = ToolBarButtonBlock->ToolTipOverride;
	}
	else
	{
		ActualToolTip = ToolBarButtonBlock->GetAction()->GetDescription();
	}

	// If a key is bound to the command, append it to the tooltip text.
	TWeakPtr<const FUICommandInfo> Action = ToolBarButtonBlock->GetAction();
	ActualToolTip = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateStatic( &Local::AppendKeyBindingToToolTip, ActualToolTip, Action ) );
	
	// If we were supplied an image than go ahead and use that, otherwise we use a null widget
	TSharedRef< SWidget > IconWidget =
		SNew( SImage )
		.Visibility( this, &SToolBarButtonBlock::GetIconVisibility, false )	
		.Image( this, &SToolBarButtonBlock::GetIconBrush );
	TSharedRef< SWidget > SmallIconWidget =
		SNew( SImage )
		.Visibility( this, &SToolBarButtonBlock::GetIconVisibility, true )	
		.Image( this, &SToolBarButtonBlock::GetSmallIconBrush );

	// Create the content for our button
	TSharedRef< SWidget > ButtonContent =

		SNew(SHorizontalBox)
		.AddMetaData<FTagMetaData>(FTagMetaData(TutorialHighlightName))

		+ SHorizontalBox::Slot()
		.FillWidth(1)
		.VAlign(VAlign_Center)
		[
			SNew( SVerticalBox )

			// Icon image
			+ SVerticalBox::Slot()
			.AutoHeight()
			.HAlign( HAlign_Center )	// Center the icon horizontally, so that large labels don't stretch out the artwork
			[
				IconWidget
			]
			+ SVerticalBox::Slot().AutoHeight()
			.HAlign( HAlign_Center )
			[
				SmallIconWidget
			]

			// Label text
			+ SVerticalBox::Slot().AutoHeight()
			.HAlign( HAlign_Center )	// Center the label text horizontally
			[
				SNew( STextBlock )
					.Visibility( LabelVisibility )
					.Text( ActualLabel )
					.TextStyle( StyleSet, ISlateStyle::Join( StyleName, ".Label" ) )	// Smaller font for tool tip labels
					.ShadowOffset( FVector2D::UnitVector )
			]
		];

	EMultiBlockLocation::Type BlockLocation = GetMultiBlockLocation();
	
	// What type of UI should we create for this block?
	EUserInterfaceActionType::Type UserInterfaceType = ToolBarButtonBlock->UserInterfaceActionType;
	if ( Action.IsValid() )
	{
		// If we have a UICommand, then this is specified in the command.
		UserInterfaceType = Action.Pin()->GetUserInterfaceType();
	}
	
	if( UserInterfaceType == EUserInterfaceActionType::Button )
	{
		FName BlockStyle = EMultiBlockLocation::ToName(ISlateStyle::Join( StyleName, ".Button" ), BlockLocation);
		ChildSlot
		[
			// Create a button
			SNew( SButton )
				.ContentPadding(0)

				// Use the tool bar item style for this button
				.ButtonStyle( StyleSet, BlockStyle )

				.ForegroundColor( FSlateColor::UseForeground() )

				.IsFocusable(bIsFocusable)
				[
					ButtonContent
				]

				// Bind the button's "on clicked" event to our object's method for this
				.OnClicked( this, &SToolBarButtonBlock::OnClicked )

				// Pass along the block's tool-tip string
				.ToolTip( FMultiBoxSettings::ToolTipConstructor.Execute( ActualToolTip, nullptr, Action.Pin() ) )
		];
	}
	else if( ensure( UserInterfaceType == EUserInterfaceActionType::ToggleButton || UserInterfaceType == EUserInterfaceActionType::RadioButton ) )
	{
		FName BlockStyle = EMultiBlockLocation::ToName(ISlateStyle::Join( StyleName, ".ToggleButton" ), BlockLocation);
		FName CheckboxStyle = ISlateStyle::Join( StyleName, ".SToolBarButtonBlock.CheckBox.Padding" );

		ChildSlot
		[
			// Create a check box
			SNew( SCheckBox )

				// Use the tool bar style for this check box
				.Style( StyleSet, BlockStyle )

				// User will have set the focusable attribute for the block, honor it
				.IsFocusable( bIsFocusable )

				// Pass along the block's tool-tip string
				.ToolTip( FMultiBoxSettings::ToolTipConstructor.Execute( ActualToolTip, nullptr, Action.Pin() ) )
				[
					ButtonContent
				]

				// Bind the button's "on checked" event to our object's method for this
				.OnCheckStateChanged( this, &SToolBarButtonBlock::OnCheckStateChanged )

				// Bind the check box's "checked" state to our user interface action
				.IsChecked( this, &SToolBarButtonBlock::OnIsChecked )

				.Padding( StyleSet->GetMargin(CheckboxStyle) )
		];
	}
	
	ChildSlot.Padding(StyleSet->GetMargin(ISlateStyle::Join( StyleName, ".SToolBarButtonBlock.Padding" )));

	// Bind our widget's enabled state to whether or not our action can execute
	SetEnabled( TAttribute< bool >( this, &SToolBarButtonBlock::IsEnabled ) );

	// Bind our widget's visible state to whether or not the button should be visible
	SetVisibility( TAttribute<EVisibility>(this, &SToolBarButtonBlock::GetBlockVisibility) );
}
	/**
	 * Registers general Editor settings.
	 *
	 * @param SettingsModule A reference to the settings module.
	 */
	void RegisterGeneralSettings( ISettingsModule& SettingsModule )
	{
		// automation
		SettingsModule.RegisterSettings("Editor", "General", "AutomationTest",
			LOCTEXT("AutomationSettingsName", "Automation"),
			LOCTEXT("AutomationSettingsDescription", "Set up automation test assets."),
			GetMutableDefault<UAutomationTestSettings>()
		);

		// region & language
		ISettingsSectionPtr RegionAndLanguageSettingsSection = SettingsModule.RegisterSettings("Editor", "General", "Internationalization",
			LOCTEXT("InternationalizationSettingsModelName", "Region & Language"),
			LOCTEXT("InternationalizationSettingsModelDescription", "Configure the editor's behavior to use a language and fit a region's culture."),
			GetMutableDefault<UInternationalizationSettingsModel>()
		);

		if (RegionAndLanguageSettingsSection.IsValid())
		{
			RegionAndLanguageSettingsSection->OnExport().BindRaw(this, &FEditorSettingsViewerModule::HandleRegionAndLanguageExport);
			RegionAndLanguageSettingsSection->OnImport().BindRaw(this, &FEditorSettingsViewerModule::HandleRegionAndLanguageImport);
			RegionAndLanguageSettingsSection->OnSaveDefaults().BindRaw(this, &FEditorSettingsViewerModule::HandleRegionAndLanguageSaveDefaults);
			RegionAndLanguageSettingsSection->OnResetDefaults().BindRaw(this, &FEditorSettingsViewerModule::HandleRegionAndLanguageResetToDefault);
			GetMutableDefault<UInternationalizationSettingsModel>()->OnSettingChanged().AddRaw(this, &FEditorSettingsViewerModule::HandleRegionAndLanguageSettingChanged);
		}

		// input bindings
		TWeakPtr<SWidget> InputBindingEditorPanel = FModuleManager::LoadModuleChecked<IInputBindingEditorModule>("InputBindingEditor").CreateInputBindingEditorPanel();
		ISettingsSectionPtr InputBindingSettingsSection = SettingsModule.RegisterSettings("Editor", "General", "InputBindings",
			LOCTEXT("InputBindingsSettingsName", "Keyboard Shortcuts"),
			LOCTEXT("InputBindingsSettingsDescription", "Configure keyboard shortcuts to quickly invoke operations."),
			InputBindingEditorPanel.Pin().ToSharedRef()
		);

		if (InputBindingSettingsSection.IsValid())
		{
			InputBindingSettingsSection->OnExport().BindRaw(this, &FEditorSettingsViewerModule::HandleInputBindingsExport);
			InputBindingSettingsSection->OnImport().BindRaw(this, &FEditorSettingsViewerModule::HandleInputBindingsImport);
			InputBindingSettingsSection->OnResetDefaults().BindRaw(this, &FEditorSettingsViewerModule::HandleInputBindingsResetToDefault);
			InputBindingSettingsSection->OnSave().BindRaw(this, &FEditorSettingsViewerModule::HandleInputBindingsSave);
		}

		// loading & saving features
		SettingsModule.RegisterSettings("Editor", "General", "LoadingSaving",
			LOCTEXT("LoadingSavingSettingsName", "Loading & Saving"),
			LOCTEXT("LoadingSavingSettingsDescription", "Change how the Editor loads and saves files."),
			GetMutableDefault<UEditorLoadingSavingSettings>()
		);

		// @todo thomass: proper settings support for source control module
		GetMutableDefault<UEditorLoadingSavingSettings>()->SccHackInitialize();

		// misc unsorted settings
		SettingsModule.RegisterSettings("Editor", "General", "UserSettings",
			LOCTEXT("UserSettingsName", "Miscellaneous"),
			LOCTEXT("UserSettingsDescription", "Customize the behavior, look and feel of the editor."),
			GetMutableDefault<UEditorPerProjectUserSettings>()
		);

		// experimental features
		SettingsModule.RegisterSettings("Editor", "General", "Experimental",
			LOCTEXT("ExperimentalettingsName", "Experimental"),
			LOCTEXT("ExperimentalSettingsDescription", "Enable and configure experimental Editor features."),
			GetMutableDefault<UEditorExperimentalSettings>()
		);
	}
//------------------------------------------------------------------------------
static void EditorCommandLineUtilsImpl::RunAssetDiffCommand(TSharedPtr<SWindow> MainEditorWindow, bool bIsRunningProjBrowser, FString CommandArgs)
{
	// if the editor is running the project browser, then the user has to first 
	// select a project (and then the editor will re-launch with this command).
	if (bIsRunningProjBrowser) 
	{
		// @TODO: can we run without loading a project?
		return;
	}

	// static so it exists past this function, but doesn't get instantiated  
	// until this function is called
	static FFauxStandaloneToolManager FauxStandaloneToolManager(MainEditorWindow);

	TMap<FString, FString> Params;
	TArray<FString> Tokens;
	TArray<FString> Switches;
	UCommandlet::ParseCommandLine(*CommandArgs, Tokens, Switches, Params);

	if (Switches.Contains("h") ||
		Switches.Contains("?") ||
		Switches.Contains("help"))
	{
		RaiseEditorMessageBox(LOCTEXT("DiffCommandHelp", "Diff/Merge Command-Line Help"), DiffCommandHelpTxt, /*bExitOnClose =*/true);
		return;
	}

	if (Switches.Contains("echo"))
	{
		RaiseEditorMessageBox(LOCTEXT("DiffCommandHelp", "Passed Command Arguments"), 
			FText::FromString(CommandArgs), /*bExitOnClose =*/true);
		return;
	}

	const int32 FilesNeededForDiff  = 2;
	const int32 FilesNeededForMerge = 4;
	const int32 MaxFilesNeeded = FilesNeededForMerge;

	FMergeAsset MergeAssets[MaxFilesNeeded] = {
		FMergeAsset(TEXT("MergeTool-Left")),
		FMergeAsset(TEXT("MergeTool-Right")),
		FMergeAsset(TEXT("MergeTool-Base")),
		FMergeAsset(TEXT("MergeTool-Merge")),
	};
	FMergeAsset& LeftAsset   = MergeAssets[0];
	FMergeAsset& ThierAsset  = LeftAsset;
	FMergeAsset& RightAsset  = MergeAssets[1];
	FMergeAsset& OurAsset    = RightAsset;
	FMergeAsset& BaseAsset   = MergeAssets[2];
	FMergeAsset& MergeResult = MergeAssets[3];

	//--------------------------------------
	// Parse file paths from command-line
	//--------------------------------------

	FCommandLineErrorReporter ErrorReporter(DiffCommandSwitch, CommandArgs);

	int32 ParsedFileCount = 0;
	for (int32 FileIndex = 0; FileIndex < Tokens.Num() && ParsedFileCount < MaxFilesNeeded; ++FileIndex)
	{
		FString& FilePath = Tokens[FileIndex];

		FMergeAsset& MergeAsset = MergeAssets[ParsedFileCount];
		if (MergeAsset.SetSourceFile(FilePath, ErrorReporter))
		{
			++ParsedFileCount;
		}
	}

	//--------------------------------------
	// Verify file count
	//--------------------------------------

	const bool bWantsMerge = (ParsedFileCount > FilesNeededForDiff);
	if (ParsedFileCount < FilesNeededForDiff)
	{
		ErrorReporter.ReportFatalError(LOCTEXT("TooFewParamsTitle", "Too Few Parameters"),
			LOCTEXT("TooFewParamsError", "At least two files are needed (for a diff)."));
	}
	else if (bWantsMerge && (ParsedFileCount < FilesNeededForMerge))
	{
		ErrorReporter.ReportFatalError(LOCTEXT("TooFewParamsTitle", "Too Few Parameters"),
			LOCTEXT("TooFewMergeParamsError", "To merge, at least two files are needed."));
	}
	else if (Tokens.Num() > FilesNeededForMerge)
	{
		ErrorReporter.ReportFatalError(LOCTEXT("TooManyParamsTitle", "Too Many Parameters"),
			FText::Format( LOCTEXT("TooManyParamsError", "There were too many command arguments supplied. The maximum files needed are {0} (for merging)"), FText::AsNumber(FilesNeededForMerge) ));
	}

	//--------------------------------------
	// Load diff/merge asset files
	//--------------------------------------

	bool bLoadSuccess = true;
	if (bWantsMerge)
	{
		bLoadSuccess &= ThierAsset.Load(ErrorReporter);
		bLoadSuccess &= OurAsset.Load(ErrorReporter);
		bLoadSuccess &= BaseAsset.Load(ErrorReporter);
	}
	else
	{
		bLoadSuccess &= LeftAsset.Load(ErrorReporter);
		bLoadSuccess &= RightAsset.Load(ErrorReporter);
	}

	//--------------------------------------
	// Verify asset types
	//--------------------------------------

	IAssetTools& AssetTools = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools").Get();
	if (bLoadSuccess)
	{
		if (LeftAsset.GetClass() != RightAsset.GetClass())
		{
			ErrorReporter.ReportFatalError(LOCTEXT("TypeMismatchTitle", "Asset Type Mismatch"),
				LOCTEXT("TypeMismatchError", "Cannot compare files of different asset types."));
		}
		else if (bWantsMerge)
		{
			UClass* AssetClass = OurAsset.GetClass();
			TWeakPtr<IAssetTypeActions> AssetActions = AssetTools.GetAssetTypeActionsForClass(AssetClass);

			if (AssetClass != BaseAsset.GetClass())
			{
				ErrorReporter.ReportFatalError(LOCTEXT("TypeMismatchTitle", "Asset Type Mismatch"),
					LOCTEXT("MergeTypeMismatchError", "Cannot merge files of different asset types."));
			}
			else if(!AssetActions.IsValid() || !AssetActions.Pin()->CanMerge())
			{
				ErrorReporter.ReportFatalError(LOCTEXT("CannotMergeTitle", "Cannot Merge"),
					FText::Format(LOCTEXT("CannotMergeError", "{0} asset files can not be merged."), FText::FromName(AssetClass->GetFName())));
			}
		}
	}

	//--------------------------------------
	// Preform diff/merge
	//--------------------------------------

	if (bLoadSuccess && !ErrorReporter.HasBlockingError())
	{
		if (bWantsMerge)
		{
			// unlike with diff'ing, for merging we rely on asset editors for
			// merging, and those windows get childed to the main window (so it
			// needs to be visible)
			//
			// @TODO: get it so asset editor windows can be shown standalone
			FauxStandaloneToolManager.Disable();

			RunAssetMerge(BaseAsset, ThierAsset, OurAsset, MergeResult);
		}
		else
		{
			AssetTools.DiffAssets(LeftAsset.GetAssetObj(), RightAsset.GetAssetObj(), LeftAsset.GetRevisionInfo(), RightAsset.GetRevisionInfo());
		}
	}
}
示例#20
0
void STutorialRoot::LaunchTutorial(UEditorTutorial* InTutorial, IIntroTutorials::ETutorialStartType InStartType, TWeakPtr<SWindow> InNavigationWindow, FSimpleDelegate InOnTutorialClosed, FSimpleDelegate InOnTutorialExited)
{
	if(InTutorial != nullptr)
	{
		CurrentTutorial = InTutorial;

		// we force a restart if this tutorial was completed
		if (GetDefault<UTutorialStateSettings>()->HaveCompletedTutorial(CurrentTutorial) && (InStartType == IIntroTutorials::ETutorialStartType::TST_CONTINUE))
		{
			InStartType = IIntroTutorials::ETutorialStartType::TST_RESTART;
		}

		bool bHaveSeenTutorial = false;
		switch (InStartType)
		{
		case IIntroTutorials::ETutorialStartType::TST_RESTART:
			CurrentTutorialStage = 0;
			break;
		case IIntroTutorials::ETutorialStartType::TST_LASTSTAGE:
			CurrentTutorialStage = FMath::Max(0, (CurrentTutorial->Stages.Num() - 1));
			break;
		default:
		case IIntroTutorials::ETutorialStartType::TST_CONTINUE:
			CurrentTutorialStage = GetDefault<UTutorialStateSettings>()->GetProgress(CurrentTutorial, bHaveSeenTutorial);
			break;
		}

		// check if we should be launching this tutorial for an asset editor
		if(InTutorial->AssetToUse.IsValid())
		{
			TArray<FString> AssetPaths;
			AssetPaths.Add(InTutorial->AssetToUse.AssetLongPathname);
			FAssetEditorManager::Get().OpenEditorsForAssets(AssetPaths);

			UObject* Asset = InTutorial->AssetToUse.ResolveObject();
			if(Asset != nullptr)
			{
				TSharedPtr<IToolkit> Toolkit = FToolkitManager::Get().FindEditorForAsset( Asset );
				if(Toolkit.IsValid())
				{
					InNavigationWindow = FSlateApplication::Get().FindWidgetWindow(Toolkit->GetToolkitHost()->GetParentWidget());

					// make sure we have a valid tutorial overlay
					if(InNavigationWindow.IsValid())
					{
						MaybeAddOverlay(InNavigationWindow.Pin().ToSharedRef());
					}
				}
			}
		}

		CurrentTutorialStartTime = FPlatformTime::Seconds();

		// launch tutorial for all windows we wrap - any tutorial can display over any window
		for(auto& TutorialWidget : TutorialWidgets)
		{
			if(TutorialWidget.Value.IsValid())
			{
				bool bIsNavigationWindow = false;
				if (!InNavigationWindow.IsValid())
				{
					bIsNavigationWindow = TutorialWidget.Value.Pin()->IsNavigationVisible();
				}
				else
				{
					bIsNavigationWindow = (TutorialWidget.Value.Pin()->GetParentWindow() == InNavigationWindow.Pin());
				}
				TutorialWidget.Value.Pin()->LaunchTutorial(bIsNavigationWindow, InOnTutorialClosed, InOnTutorialExited);
			}
		}

		if (CurrentTutorial != nullptr)
		{
			CurrentTutorial->HandleTutorialLaunched();
		}

		if (CurrentTutorial != nullptr && CurrentTutorialStage < CurrentTutorial->Stages.Num())
		{
			CurrentTutorial->HandleTutorialStageStarted(CurrentTutorial->Stages[CurrentTutorialStage].Name);
		}
	}
}