// Copyright Epic Games, Inc. All Rights Reserved. #include "MuCOE/CustomizableObjectDetails.h" #include "DetailLayoutBuilder.h" #include "DetailWidgetRow.h" #include "IDetailsView.h" #include "MuCO/CustomizableObject.h" #include "MuCO/CustomizableObjectPrivate.h" #include "MuCOE/GraphTraversal.h" #include "MuCOE/Nodes/CustomizableObjectNodeObject.h" #include "MuR/Model.h" #include "MuR/Parameters.h" #include "MuR/Ptr.h" class ITableRow; #define LOCTEXT_NAMESPACE "CustomizableObjectDetails" TSharedRef FCustomizableObjectDetails::MakeInstance() { return MakeShareable( new FCustomizableObjectDetails ); } class FStateDetailsNode { public: FStateDetailsNode() { StateIndex = -1; ParameterIndex = -1; } TSharedPtr Model; int StateIndex; int ParameterIndex; TSharedPtr GetName() { FString res; if (ParameterIndex<0) { res = Model->GetStateName( StateIndex ); } else { TSharedPtr TempParams = mu::FModel::NewParameters(Model); res = TempParams->GetName( ParameterIndex ); } return MakeShareable( new FString( res ) ); } TArray> GetChildrenList() { TArray> ChildrenList; // Is it a state node? if (ParameterIndex<0) { int ParameterCount = Model->GetStateParameterCount( StateIndex ); for ( int i=0; i SlateDetailsNode = MakeShareable( new FStateDetailsNode ); SlateDetailsNode->Model = Model; SlateDetailsNode->StateIndex = StateIndex; SlateDetailsNode->ParameterIndex = Model->GetStateParameterIndex( StateIndex, i ); ChildrenList.Add( SlateDetailsNode ); } } return ChildrenList; } }; void FCustomizableObjectDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder ) { TSharedPtr DetailsView = DetailBuilder.GetDetailsViewSharedPtr(); if (DetailsView && DetailsView->GetSelectedObjects().Num()) { CustomizableObject = Cast(DetailsView->GetSelectedObjects()[0].Get()); } IDetailCategoryBuilder& CustomizableObjectCategory = DetailBuilder.EditCategory("CustomizableObject"); IDetailCategoryBuilder& StatesCategory = DetailBuilder.EditCategory( "States" ); IDetailCategoryBuilder& VersioningCategory = DetailBuilder.EditCategory( "Versioning" ); //StatesCategory.CategoryIcon( "ActorClassIcon.CustomizableObject" ); DetailBuilder.HideProperty("States"); DetailBuilder.HideProperty("CustomizableObjectClassTags"); DetailBuilder.HideProperty("PopulationClassTags"); // Make the tree get automatically updated each time we compile the host CO if (CustomizableObject && !CustomizableObject->GetPrivate()->PostCompileDelegate.IsBoundToObject(this)) { CustomizableObject->GetPrivate()->PostCompileDelegate.AddSP(this, &FCustomizableObjectDetails::UpdateTree); } // Cache the states defined in the CO UpdateTree(); StatesCategory.AddCustomRow( LOCTEXT("FCustomizableObjectDetails States", "States") ) [ SNew( SVerticalBox ) + SVerticalBox::Slot() .Padding( 2.0f ) [ SAssignNew(StatesTree, STreeView>) .SelectionMode(ESelectionMode::Single) .TreeItemsSource( &RootTreeItems ) // Called to child items for any given parent item .OnGetChildren( this, &FCustomizableObjectDetails::OnGetChildrenForStateTree ) // Generates the actual widget for a tree item .OnGenerateRow( this, &FCustomizableObjectDetails::OnGenerateRowForStateTree ) .HeaderRow ( SNew(SHeaderRow) .Visibility(EVisibility::Collapsed) + SHeaderRow::Column(TEXT("State")) .DefaultLabel(NSLOCTEXT("CustomizableObjectDetails","State","State")) ) ] ]; StatesTree->SetIsRightClickScrollingEnabled(false); TSharedRef VersionBridgeProperty = DetailBuilder.GetProperty("VersionBridge"); if (VersionBridgeProperty->IsValidHandle() && CustomizableObject) { if (CustomizableObject->IsChildObject()) { VersionBridgeProperty->MarkHiddenByCustomization(); } else { VersionBridgeProperty->MarkResetToDefaultCustomized(); } } TSharedRef VersionStructProperty = DetailBuilder.GetProperty("VersionStruct"); if (VersionStructProperty->IsValidHandle() && CustomizableObject) { if (CustomizableObject->IsChildObject()) { VersionStructProperty->MarkResetToDefaultCustomized(); } else { VersionStructProperty->MarkHiddenByCustomization(); } } } void FCustomizableObjectDetails::UpdateTree() { UCustomizableObject* RootObject = GraphTraversal::GetRootObject(CustomizableObject); if (RootObject && RootObject->GetPrivate()->GetModel() ) { RootTreeItems.SetNumUninitialized(0); const uint32 NumElements = RootObject->GetPrivate()->GetModel()->GetStateCount(); for ( uint32 i=0; i SlateDetailsNode = MakeShareable( new FStateDetailsNode ); SlateDetailsNode->Model = RootObject->GetPrivate()->GetModel(); SlateDetailsNode->StateIndex = i; RootTreeItems.Add( SlateDetailsNode ); } } if (StatesTree) { StatesTree->RequestTreeRefresh(); } } /** The item used for visualizing the class in the tree. */ class SStateItem : public STableRow< TSharedPtr > { public: SLATE_BEGIN_ARGS( SStateItem ) : _StateName() , _OwnerTableView() , _HighlightText(NULL) , _TextColor(FLinearColor(1.0f, 1.0f, 1.0f, 1.0f)) {} /** The classname this item contains. */ SLATE_ARGUMENT( TSharedPtr, StateName ) /** The table that owns this item. */ SLATE_ARGUMENT( TSharedPtr, OwnerTableView ) /** The text this item should highlight, if any. */ SLATE_ARGUMENT( const FString*, HighlightText ) /** The color text this item will use. */ SLATE_ARGUMENT( FSlateColor, TextColor ) /** The node this item is associated with. */ SLATE_ARGUMENT( TSharedPtr, AssociatedNode) SLATE_END_ARGS() /** * Construct the widget * * @param InArgs A declaration from which to construct the widget */ void Construct( const FArguments& InArgs ) { StateName = InArgs._StateName; AssociatedNode = InArgs._AssociatedNode; FMargin Padding = { 0.0f, 3.0f, 6.0f, 3.0f }; if (AssociatedNode->ParameterIndex != INDEX_NONE) { Padding = { 10.0f, 3.0f, 6.0f, 3.0f }; } this->ChildSlot [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) .HAlign(HAlign_Right) [ SNew( SExpanderArrow, SharedThis(this) ) ] +SHorizontalBox::Slot() .AutoWidth() .Padding( Padding ) .VAlign(VAlign_Center) .HAlign(HAlign_Left) [ SNew( STextBlock ) .Text( FText::FromString(*StateName.Get()) ) //.HighlightString(*InArgs._HighlightText) //.ColorAndOpacity( this, &SClassItem::GetTextColor) ] //+SHorizontalBox::Slot() // .HAlign(HAlign_Right) // .VAlign(VAlign_Center) // .Padding( 0.0f, 0.0f, 6.0f, 0.0f ) // [ // SNew( SComboButton ) // .ContentPadding(FMargin(2.0f)) // //.OnGetMenuContent(this, &SClassItem::GenerateDropDown) // ] ]; TextColor = InArgs._TextColor; STableRow< TSharedPtr >::ConstructInternal( STableRow::FArguments() .ShowSelection(true), InArgs._OwnerTableView.ToSharedRef() ); } private: /** * Generates the drop down menu for the item. * * @return The drop down menu widget. */ /* TSharedRef GenerateDropDown() { // Empty list of commands. TSharedPtr< FUICommandList > Commands; const bool bShouldCloseWindowAfterMenuSelection = true; // Set the menu to automatically close when the user commits to a choice FMenuBuilder MenuBuilder( bShouldCloseWindowAfterMenuSelection, Commands); { if (UClass* Class = AssociatedNode->Class.Get()) { bool bIsBlueprint(false); bool bHasBlueprint(false); ClassViewer::Helpers::GetClassInfo(Class, bIsBlueprint, bHasBlueprint); bHasBlueprint = AssociatedNode->Blueprint.IsValid(); if (bIsBlueprint) { FUIAction Action( FExecuteAction::CreateStatic( &ClassViewer::Helpers::CreateBlueprint, Class ) ); MenuBuilder.AddMenuEntry(TEXT("Create Blueprint..."), TEXT("Creates a new Blueprint from the current one."), NAME_None, Action); } if (bHasBlueprint) { MenuBuilder.AddMenuSeparator(); FUIAction Action( FExecuteAction::CreateStatic( &ClassViewer::Helpers::OpenBlueprintTool, ClassViewer::Helpers::GetBlueprint(Class) ) ); MenuBuilder.AddMenuEntry(TEXT("Open Blueprint Editor"), TEXT("Open the Blueprint in the editor."), NAME_None, Action); } if (bHasBlueprint) { MenuBuilder.AddMenuSeparator(); FUIAction Action( FExecuteAction::CreateStatic( &ClassViewer::Helpers::FindInContentBrowser, ClassViewer::Helpers::GetBlueprint(Class), Class ) ); MenuBuilder.AddMenuEntry(TEXT("Find In Content Browser"), TEXT("Find in Content Browser"), NAME_None, Action); } } } return MenuBuilder.MakeWidget(); } */ /** Returns the text color for the item based on if it is selected or not. */ FSlateColor GetTextColor() const { const TSharedPtr< ITypedTableView< TSharedPtr > > OwnerWidget = OwnerTablePtr.Pin(); const TSharedPtr* MyItem = OwnerWidget->Private_ItemFromWidget( this ); const bool bIsSelected = OwnerWidget->Private_IsItemSelected( *MyItem ); if(bIsSelected) { return FSlateColor::UseForeground(); } return TextColor; } private: /** The class name for which this item is associated with. */ TSharedPtr StateName; /** The text color for this item. */ FSlateColor TextColor; /** The Class Viewer Node this item is associated with. */ TSharedPtr< FStateDetailsNode > AssociatedNode; }; TSharedRef< ITableRow > FCustomizableObjectDetails::OnGenerateRowForStateTree( TSharedPtr Item, const TSharedRef< STableViewBase >& OwnerTable ) { // If the item was accepted by the filter, leave it bright, otherwise dim it. float AlphaValue = 1.0f; TSharedRef< ITableRow > ReturnRow = SNew(SStateItem) .StateName(Item->GetName()) //.HighlightText(&SearchBox->GetText()) .TextColor(FLinearColor(1.0f, 1.0f, 1.0f, AlphaValue)) .AssociatedNode(Item) .OwnerTableView( OwnerTable ); // Expand the item if needed. //bool* bIsExpanded = ExpansionStateMap.Find( Item->GetName() ); //if( bIsExpanded && *bIsExpanded ) //{ // StatesTree->SetItemExpansion( Item, *bIsExpanded ); //} return ReturnRow; } void FCustomizableObjectDetails::OnGetChildrenForStateTree( TSharedPtr InParent, TArray< TSharedPtr< FStateDetailsNode > >& OutChildren ) { // Simply return the children, it's already setup. OutChildren = InParent->GetChildrenList(); } #undef LOCTEXT_NAMESPACE