You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3209340 on 2016/11/23 by Ben.Marsh Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h. Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms. * Every header now includes everything it needs to compile. * There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first. * There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h. * Every .cpp file includes its matching .h file first. * This helps validate that each header is including everything it needs to compile. * No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more. * You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there. * There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible. * No engine code explicitly includes a precompiled header any more. * We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies. * PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files. Tool used to generate this transform is at Engine\Source\Programs\IncludeTool. [CL 3209342 by Ben Marsh in Main branch]
400 lines
13 KiB
C++
400 lines
13 KiB
C++
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Framework/MultiBox/MultiBoxCustomization.h"
|
|
#include "Misc/ConfigCacheIni.h"
|
|
#include "Serialization/JsonReader.h"
|
|
#include "Serialization/JsonSerializer.h"
|
|
#include "Framework/Commands/InputBindingManager.h"
|
|
#include "Widgets/Layout/SBorder.h"
|
|
#include "Misc/RemoteConfigIni.h"
|
|
#include "Framework/Commands/UICommandDragDropOp.h"
|
|
|
|
void SCustomToolbarPreviewWidget::Construct( const FArguments& InArgs )
|
|
{
|
|
Content = InArgs._Content.Widget;
|
|
}
|
|
|
|
void SCustomToolbarPreviewWidget::BuildMultiBlockWidget(const ISlateStyle* StyleSet, const FName& StyleName)
|
|
{
|
|
ChildSlot
|
|
[
|
|
SNew( SBorder )
|
|
.Padding(0)
|
|
.BorderImage( FCoreStyle::Get().GetBrush("NoBorder") )
|
|
.HAlign(HAlign_Center)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
Content.ToSharedRef()
|
|
]
|
|
];
|
|
|
|
// Add this widget to the search list of the multibox and hide it
|
|
if (MultiBlock->GetSearchable())
|
|
OwnerMultiBoxWidget.Pin()->AddSearchElement(this->AsWidget(), FText::GetEmpty());
|
|
}
|
|
|
|
void SMultiBlockDragHandle::Construct( const FArguments& InArgs, TSharedRef<SMultiBoxWidget> InBaseWidget, TSharedRef<const FMultiBlock> InBlock, FName CustomizationName )
|
|
{
|
|
BaseWidget = InBaseWidget;
|
|
Block = InBlock;
|
|
MultiBoxCustomizationName = CustomizationName;
|
|
}
|
|
|
|
FReply SMultiBlockDragHandle::OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
if( MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton && Block->GetAction().IsValid() )
|
|
{
|
|
return FReply::Handled().DetectDrag( SharedThis(this), MouseEvent.GetEffectingButton() );
|
|
}
|
|
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
void SMultiBlockDragHandle::OnDragEnter( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent )
|
|
{
|
|
if ( DragDropEvent.GetOperationAs<FUICommandDragDropOp>().IsValid() )
|
|
{
|
|
BaseWidget.Pin()->OnCustomCommandDragEnter( Block.ToSharedRef(), MyGeometry, DragDropEvent );
|
|
}
|
|
}
|
|
|
|
FReply SMultiBlockDragHandle::OnDragOver( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent )
|
|
{
|
|
if ( DragDropEvent.GetOperationAs<FUICommandDragDropOp>().IsValid() )
|
|
{
|
|
BaseWidget.Pin()->OnCustomCommandDragged( Block.ToSharedRef(), MyGeometry, DragDropEvent );
|
|
return FReply::Handled();
|
|
}
|
|
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
FReply SMultiBlockDragHandle::OnDrop( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent )
|
|
{
|
|
if ( DragDropEvent.GetOperationAs<FUICommandDragDropOp>().IsValid() )
|
|
{
|
|
BaseWidget.Pin()->OnCustomCommandDropped();
|
|
return FReply::Handled();
|
|
}
|
|
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
FReply SMultiBlockDragHandle::OnDragDetected( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
TSharedRef<FUICommandDragDropOp> NewOp = FUICommandDragDropOp::New(
|
|
Block->GetAction().ToSharedRef(),
|
|
MultiBoxCustomizationName,
|
|
Block->MakeWidget( BaseWidget.Pin().ToSharedRef(), EMultiBlockLocation::None, Block->HasIcon() )->AsWidget(),
|
|
MyGeometry.AbsolutePosition-MouseEvent.GetScreenSpacePosition()
|
|
);
|
|
|
|
NewOp->SetOnDropNotification( FSimpleDelegate::CreateSP( BaseWidget.Pin().ToSharedRef(), &SMultiBoxWidget::OnDropExternal ) );
|
|
|
|
TSharedRef<FDragDropOperation> DragDropOp = NewOp;
|
|
return FReply::Handled().BeginDragDrop( DragDropOp );
|
|
}
|
|
|
|
TSharedRef< class IMultiBlockBaseWidget > FDropPreviewBlock::ConstructWidget() const
|
|
{
|
|
return
|
|
SNew( SCustomToolbarPreviewWidget )
|
|
.Visibility( EVisibility::Hidden )
|
|
.Content()
|
|
[
|
|
ActualWidget->AsWidget()
|
|
];
|
|
|
|
}
|
|
|
|
void FMultiBoxCustomizationData::LoadCustomizedBlocks()
|
|
{
|
|
Transactions.Empty();
|
|
|
|
FString Content;
|
|
|
|
GConfig->GetString(*GetConfigSectionName(), *CustomizationName.ToString(), Content, GEditorPerProjectIni);
|
|
|
|
TSharedPtr<FJsonObject> SavedData;
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( FRemoteConfig::ReplaceIniSpecialCharWithChar(Content).ReplaceEscapedCharWithChar() );
|
|
bool bResult = FJsonSerializer::Deserialize( Reader, SavedData );
|
|
|
|
if( bResult && SavedData.IsValid() )
|
|
{
|
|
TArray<TSharedPtr<FJsonValue> > CustomBlockData = SavedData->GetArrayField( TEXT("CustomBlocks") );
|
|
for (TArray<TSharedPtr<FJsonValue> >::TConstIterator It(CustomBlockData); It; ++It)
|
|
{
|
|
TSharedPtr<FJsonObject> SavedCommand = (*It)->AsObject();
|
|
|
|
if( SavedCommand.IsValid() )
|
|
{
|
|
FString CommandName = SavedCommand->GetStringField( TEXT("CommandName") );
|
|
FString Context = SavedCommand->GetStringField( TEXT("Context") );
|
|
int32 Index = FMath::TruncToInt( SavedCommand->GetNumberField( TEXT("Index") ) );
|
|
FCustomBlockTransaction::ETransactionType TransType = (FCustomBlockTransaction::ETransactionType)FMath::TruncToInt( SavedCommand->GetNumberField("TransactionType") );
|
|
|
|
if( !CommandName.IsEmpty() && !Context.IsEmpty() && Index >= 0 )
|
|
{
|
|
const TSharedPtr< const FUICommandInfo> FoundCommand = FInputBindingManager::Get().FindCommandInContext( FName( *Context ), FName( *CommandName ) );
|
|
if( FoundCommand.IsValid() )
|
|
{
|
|
FCustomBlockTransaction NewTransaction;
|
|
if( TransType == FCustomBlockTransaction::Add )
|
|
{
|
|
NewTransaction = FCustomBlockTransaction::CreateAdd( FoundCommand.ToSharedRef(), Index );
|
|
}
|
|
else
|
|
{
|
|
NewTransaction = FCustomBlockTransaction::CreateRemove( FoundCommand.ToSharedRef(), Index );
|
|
}
|
|
|
|
Transactions.Add( NewTransaction );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FString FMultiBoxCustomizationData::GetConfigSectionName() const
|
|
{
|
|
return TEXT("CustomMultiBoxes1_0");
|
|
}
|
|
|
|
void FMultiBoxCustomizationData::RemoveTransactionAt(int32 RemoveIndex)
|
|
{
|
|
// Copy off the transaction we are going to remove.
|
|
FCustomBlockTransaction TransToRemove = Transactions[RemoveIndex];
|
|
const int32 TransToRemoveIndex = TransToRemove.BlockIndex;
|
|
|
|
// Remove the transaction
|
|
Transactions.RemoveAt( RemoveIndex );
|
|
|
|
// Iterate over all transactions after this one to fix up indices.
|
|
for( int32 StartIndex = RemoveIndex; StartIndex < Transactions.Num(); ++StartIndex )
|
|
{
|
|
int32& CheckIndex = Transactions[StartIndex].BlockIndex;
|
|
|
|
// If the index is greater than or equal to the index we are removing, this transaction is affected by this removal.
|
|
if( CheckIndex >= TransToRemoveIndex )
|
|
{
|
|
// If the removed transaction was an add, subtract 1 from the index of this transaction. Otherwise, add one.
|
|
if( TransToRemove.TransactionType == FCustomBlockTransaction::Add )
|
|
{
|
|
--CheckIndex;
|
|
}
|
|
else
|
|
{
|
|
++CheckIndex;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FMultiBoxCustomizationData::RemoveDuplicateTransaction()
|
|
{
|
|
if( Transactions.Num() > 0 )
|
|
{
|
|
FCustomBlockTransaction LastTrans = Transactions.Last();
|
|
|
|
int32 CheckIndex = LastTrans.BlockIndex;
|
|
|
|
// Skip the last item
|
|
for( int32 TransIndex = Transactions.Num()-2; TransIndex >= 0; --TransIndex )
|
|
{
|
|
FCustomBlockTransaction CurrentTrans = Transactions[TransIndex];
|
|
|
|
//ensure( !(CurrentTrans.TransactionType == LastTrans.TransactionType && CurrentTrans.Command == LastTrans.Command ) );
|
|
|
|
if( CurrentTrans.Command == LastTrans.Command &&
|
|
CurrentTrans.BlockIndex == CheckIndex &&
|
|
CurrentTrans.TransactionType != LastTrans.TransactionType )
|
|
{
|
|
RemoveTransactionAt( Transactions.Num()-1 );
|
|
RemoveTransactionAt( TransIndex );
|
|
|
|
return true;
|
|
}
|
|
|
|
if( CheckIndex >= CurrentTrans.BlockIndex )
|
|
{
|
|
if( CurrentTrans.TransactionType == FCustomBlockTransaction::Add )
|
|
{
|
|
--CheckIndex;
|
|
}
|
|
else
|
|
{
|
|
++CheckIndex;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FMultiBoxCustomizationData::RemoveUnnecessaryTransactions(const TArray< TSharedRef< const FMultiBlock > >& AllBlocks)
|
|
{
|
|
// A local struct describing the state of the menu
|
|
struct FCustomizationState
|
|
{
|
|
FCustomizationState(const TArray< TSharedRef< const FMultiBlock > >& InAllBlocks)
|
|
{
|
|
for ( int32 BlockIdx = 0; BlockIdx < InAllBlocks.Num(); ++BlockIdx )
|
|
{
|
|
StateData.Add(InAllBlocks[BlockIdx]->GetAction());
|
|
}
|
|
}
|
|
|
|
// Applies the inverse operation of the given transaction to mutate the state
|
|
void ApplyInverseOfTransaction(const FCustomBlockTransaction& Trans)
|
|
{
|
|
if ( Trans.TransactionType == FCustomBlockTransaction::Add )
|
|
{
|
|
// Remove on an add operation
|
|
if ( ensure(StateData.IsValidIndex(Trans.BlockIndex)) )
|
|
{
|
|
ensure(StateData[Trans.BlockIndex] == Trans.Command);
|
|
|
|
StateData.RemoveAt(Trans.BlockIndex);
|
|
}
|
|
}
|
|
else if ( Trans.TransactionType == FCustomBlockTransaction::Remove )
|
|
{
|
|
// Add on a remove transaction
|
|
StateData.Insert(Trans.Command, Trans.BlockIndex);
|
|
}
|
|
}
|
|
|
|
// Compares two states. If all elements of the states are the same then they are "equal"
|
|
bool operator==(const FCustomizationState& Other) const
|
|
{
|
|
if ( StateData.Num() != Other.StateData.Num() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const int32 Length = StateData.Num();
|
|
for ( int32 StateIdx = 0; StateIdx < Length; ++StateIdx )
|
|
{
|
|
if ( StateData[StateIdx] != Other.StateData[StateIdx] )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
TArray<TWeakPtr<const FUICommandInfo>> StateData;
|
|
};
|
|
|
|
if( Transactions.Num() > 0 )
|
|
{
|
|
// Take the current state and start applying the inverse of each transaction to it to determine the states before the current.
|
|
// If we found any state that is identical to the current state, all transactions between that state and the current state are unnecessary, so remove them
|
|
|
|
// Record the initial (current) state and initialize the Test state.
|
|
FCustomizationState InitialState(AllBlocks);
|
|
FCustomizationState TestState = InitialState;
|
|
|
|
// Walk backwards through all transactions, applying the inverse of each transaction to the test state
|
|
for ( int32 TransIdx = Transactions.Num() - 1; TransIdx >= 0; --TransIdx )
|
|
{
|
|
TestState.ApplyInverseOfTransaction(Transactions[TransIdx]);
|
|
|
|
// If the test state is equal to the current state, all transactions between are unnecessary. Remove them.
|
|
if ( TestState == InitialState )
|
|
{
|
|
for ( int32 RemoveIdx = Transactions.Num() - 1; RemoveIdx >= TransIdx; --RemoveIdx )
|
|
{
|
|
RemoveTransactionAt(RemoveIdx);
|
|
}
|
|
|
|
// Return true to indicate we actually removed something.
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// All transactions were necessary to form the final state. Return false.
|
|
return false;
|
|
}
|
|
|
|
void FMultiBoxCustomizationData::SaveCustomizedBlocks()
|
|
{
|
|
FString SaveData;
|
|
TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create( &SaveData );
|
|
|
|
Writer->WriteObjectStart();
|
|
Writer->WriteArrayStart(TEXT("CustomBlocks"));
|
|
for (TArray<FCustomBlockTransaction>::TConstIterator It(Transactions); It; ++It)
|
|
{
|
|
const FCustomBlockTransaction& Transaction = *It;
|
|
|
|
if( Transaction.Command.IsValid() )
|
|
{
|
|
const FUICommandInfo& Command = *Transaction.Command.Pin();
|
|
|
|
Writer->WriteObjectStart();
|
|
Writer->WriteValue(TEXT("CommandName"), Command.GetCommandName().ToString() );
|
|
Writer->WriteValue(TEXT("Context"), Command.GetBindingContext().ToString() );
|
|
Writer->WriteValue(TEXT("Index"), (float)Transaction.BlockIndex );
|
|
Writer->WriteValue(TEXT("TransactionType"), (float)Transaction.TransactionType );
|
|
Writer->WriteObjectEnd();
|
|
}
|
|
}
|
|
|
|
Writer->WriteArrayEnd();
|
|
Writer->WriteObjectEnd();
|
|
Writer->Close();
|
|
|
|
GConfig->SetString( *GetConfigSectionName(), *CustomizationName.ToString(), *FRemoteConfig::ReplaceIniCharWithSpecialChar(SaveData).ReplaceCharWithEscapedChar(), GEditorPerProjectIni );
|
|
}
|
|
|
|
void FMultiBoxCustomizationData::BlockRemoved( TSharedRef< const FMultiBlock> RemovedBlock, int32 Index, const TArray< TSharedRef< const FMultiBlock > >& AllBlocks )
|
|
{
|
|
FCustomBlockTransaction Remove = FCustomBlockTransaction::CreateRemove( RemovedBlock->GetAction().ToSharedRef(), Index );
|
|
|
|
SaveTransaction( Remove, AllBlocks );
|
|
|
|
}
|
|
|
|
void FMultiBoxCustomizationData::BlockAdded( TSharedRef< const FMultiBlock > AddedBlock, int32 Index, const TArray< TSharedRef< const FMultiBlock > >& AllBlocks )
|
|
{
|
|
FCustomBlockTransaction Add = FCustomBlockTransaction::CreateAdd( AddedBlock->GetAction().ToSharedRef(), Index );
|
|
|
|
SaveTransaction( Add, AllBlocks );
|
|
}
|
|
|
|
#define DEBUG_TRANSACTIONS 0
|
|
#if DEBUG_TRANSACTIONS
|
|
static void PrintTransactions( const TArray<FCustomBlockTransaction>& Transactions )
|
|
{
|
|
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("==========BEGIN TRANSACTIONS=======\n"));
|
|
for( int32 i = 0; i < Transactions.Num(); ++i )
|
|
{
|
|
const FCustomBlockTransaction& Trans = Transactions[i];
|
|
|
|
FString TransType = Trans.TransactionType == FCustomBlockTransaction::Add ? TEXT("+") : TEXT("-");
|
|
FPlatformMisc::LowLevelOutputDebugStringf( TEXT("%s(%s,%d)\n"), *TransType, *Trans.Command.Pin()->GetCommandName().ToString(), Trans.BlockIndex );
|
|
}
|
|
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("============END TRANSACTIONS=======\n"));
|
|
}
|
|
#endif
|
|
|
|
void FMultiBoxCustomizationData::SaveTransaction( const struct FCustomBlockTransaction& Transaction, const TArray< TSharedRef< const FMultiBlock > >& AllBlocks )
|
|
{
|
|
Transactions.Add( Transaction );
|
|
|
|
while( RemoveDuplicateTransaction() );
|
|
while( RemoveUnnecessaryTransactions(AllBlocks) );
|
|
|
|
#if DEBUG_TRANSACTIONS
|
|
PrintTransactions( Transactions );
|
|
#endif
|
|
|
|
SaveCustomizedBlocks();
|
|
}
|