2014-12-07 19:09:38 -05:00
|
|
|
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
#include "DetailCustomizationsPrivatePCH.h"
|
|
|
|
|
#include "SoundDefinitions.h"
|
|
|
|
|
#include "DialogueStructsCustomizations.h"
|
|
|
|
|
#include "DialogueWaveWidgets.h"
|
|
|
|
|
#include "AssetThumbnail.h"
|
2014-11-04 06:12:25 -05:00
|
|
|
#include "Sound/DialogueWave.h"
|
2014-11-12 04:58:53 -05:00
|
|
|
#include "Sound/DialogueVoice.h"
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
#define LOCTEXT_NAMESPACE "DialogueWaveDetails"
|
|
|
|
|
|
2014-06-04 10:16:14 -04:00
|
|
|
TSharedRef<IPropertyTypeCustomization> FDialogueContextStructCustomization::MakeInstance()
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
return MakeShareable( new FDialogueContextStructCustomization );
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-04 11:16:24 -04:00
|
|
|
void FDialogueContextStructCustomization::CustomizeHeader( TSharedRef<IPropertyHandle> StructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils )
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
if( StructPropertyHandle->IsValidHandle() )
|
|
|
|
|
{
|
|
|
|
|
HeaderRow
|
|
|
|
|
[
|
|
|
|
|
SNew( SBorder )
|
|
|
|
|
.BorderImage( FEditorStyle::GetBrush("DialogueWaveDetails.HeaderBorder") )
|
|
|
|
|
[
|
|
|
|
|
SNew( SVerticalBox )
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
StructPropertyHandle->CreatePropertyNameWidget()
|
|
|
|
|
]
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
SNew( SDialogueContextHeaderWidget, StructPropertyHandle, StructCustomizationUtils.GetThumbnailPool().ToSharedRef() )
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-04 11:16:24 -04:00
|
|
|
void FDialogueContextStructCustomization::CustomizeChildren( TSharedRef<IPropertyHandle> StructPropertyHandle, class IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils )
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
if( StructPropertyHandle->IsValidHandle() )
|
|
|
|
|
{
|
|
|
|
|
const TSharedPtr<IPropertyHandle> SpeakerPropertyHandle = StructPropertyHandle->GetChildHandle("Speaker");
|
|
|
|
|
ChildBuilder.AddChildProperty(SpeakerPropertyHandle.ToSharedRef());
|
|
|
|
|
|
|
|
|
|
const TSharedPtr<IPropertyHandle> TargetsPropertyHandle = StructPropertyHandle->GetChildHandle("Targets");
|
|
|
|
|
ChildBuilder.AddChildProperty(TargetsPropertyHandle.ToSharedRef());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class SSpeakerDropDown : public SCompoundWidget
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
SLATE_BEGIN_ARGS( SSpeakerDropDown ) {}
|
|
|
|
|
SLATE_END_ARGS()
|
|
|
|
|
|
|
|
|
|
void Construct( const FArguments& InArgs, const TSharedRef<IPropertyHandle>& InPropertyHandle, const TSharedRef<FAssetThumbnailPool>& InAssetThumbnailPool );
|
2014-06-13 06:14:46 -04:00
|
|
|
virtual void Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime ) override;
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void OnSelectionChanged(TSharedPtr<UDialogueVoice*> Speaker, ESelectInfo::Type SelectInfo);
|
|
|
|
|
TSharedRef<SWidget> MakeComboButtonItemWidget(TSharedPtr<UDialogueVoice*> Speaker);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
TSharedPtr<IPropertyHandle> DialogueWaveParameterPropertyHandle;
|
|
|
|
|
TSharedPtr<FAssetThumbnailPool> AssetThumbnailPool;
|
|
|
|
|
TSharedPtr< SComboBox< TSharedPtr<UDialogueVoice*> > > ComboBox;
|
|
|
|
|
TArray< TSharedPtr<UDialogueVoice*> > OptionsSource;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void SSpeakerDropDown::Construct( const FArguments& InArgs, const TSharedRef<IPropertyHandle>& InPropertyHandle, const TSharedRef<FAssetThumbnailPool>& InAssetThumbnailPool )
|
|
|
|
|
{
|
|
|
|
|
DialogueWaveParameterPropertyHandle = InPropertyHandle;
|
|
|
|
|
AssetThumbnailPool = InAssetThumbnailPool;
|
|
|
|
|
|
|
|
|
|
const TSharedPtr<IPropertyHandle> ContextPropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("Context");
|
|
|
|
|
const TSharedPtr<IPropertyHandle> SpeakerPropertyHandle = ContextPropertyHandle->GetChildHandle("Speaker");
|
|
|
|
|
|
|
|
|
|
TSharedRef<SDialogueVoicePropertyEditor> SpeakerPropertyEditor =
|
|
|
|
|
SNew( SDialogueVoicePropertyEditor, SpeakerPropertyHandle.ToSharedRef(), InAssetThumbnailPool )
|
|
|
|
|
.IsEditable(false)
|
|
|
|
|
.ShouldCenterThumbnail(true);
|
|
|
|
|
|
|
|
|
|
FSlateFontInfo Font = IDetailLayoutBuilder::GetDetailFont();
|
|
|
|
|
|
|
|
|
|
ChildSlot
|
|
|
|
|
[
|
|
|
|
|
SNew( SVerticalBox )
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.Padding(2.0f)
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
SAssignNew( ComboBox, SComboBox< TSharedPtr<UDialogueVoice*> > )
|
|
|
|
|
.ButtonStyle( FEditorStyle::Get(), "PropertyEditor.AssetComboStyle" )
|
|
|
|
|
.ForegroundColor(FEditorStyle::GetColor("PropertyEditor.AssetName.ColorAndOpacity"))
|
|
|
|
|
.OptionsSource( &OptionsSource )
|
|
|
|
|
.OnGenerateWidget( this, &SSpeakerDropDown::MakeComboButtonItemWidget )
|
|
|
|
|
.OnSelectionChanged( this, &SSpeakerDropDown::OnSelectionChanged )
|
|
|
|
|
[
|
|
|
|
|
SpeakerPropertyEditor
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.Padding( 2.0f )
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
// Voice Description
|
|
|
|
|
SNew( STextBlock )
|
|
|
|
|
.Font( Font )
|
|
|
|
|
.Text( SpeakerPropertyEditor, &SDialogueVoicePropertyEditor::GetDialogueVoiceDescription )
|
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SSpeakerDropDown::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
|
|
|
|
|
{
|
|
|
|
|
// Get dialogue wave.
|
|
|
|
|
const TSharedPtr<IPropertyHandle> DialogueWavePropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("DialogueWave");
|
|
|
|
|
const UDialogueWave* DialogueWave = NULL;
|
|
|
|
|
if( DialogueWavePropertyHandle->IsValidHandle() )
|
|
|
|
|
{
|
|
|
|
|
UObject* Object = NULL;
|
|
|
|
|
DialogueWavePropertyHandle->GetValue(Object);
|
|
|
|
|
DialogueWave = Cast<UDialogueWave>(Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get context.
|
|
|
|
|
const TSharedPtr<IPropertyHandle> ContextPropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("Context");
|
|
|
|
|
|
|
|
|
|
// Get speaker.
|
|
|
|
|
const TSharedPtr<IPropertyHandle> SpeakerPropertyHandle = ContextPropertyHandle->GetChildHandle("Speaker");
|
|
|
|
|
const UDialogueVoice* Speaker = NULL;
|
|
|
|
|
{
|
|
|
|
|
UObject* Object = NULL;
|
|
|
|
|
SpeakerPropertyHandle->GetValue(Object);
|
|
|
|
|
Speaker = Cast<UDialogueVoice>(Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Gather unique speaker options.
|
|
|
|
|
TArray<UDialogueVoice*> UniqueSpeakers;
|
|
|
|
|
if(DialogueWave)
|
|
|
|
|
{
|
|
|
|
|
for(int32 i = 0; i < DialogueWave->ContextMappings.Num(); ++i)
|
|
|
|
|
{
|
|
|
|
|
bool bIsValidSpeaker = ( DialogueWave->ContextMappings[i].Context.Speaker != NULL );
|
|
|
|
|
|
|
|
|
|
bool bIsValidTargetSet = true;
|
|
|
|
|
for(int32 j = 0; j < DialogueWave->ContextMappings[i].Context.Targets.Num(); ++j)
|
|
|
|
|
{
|
|
|
|
|
bIsValidTargetSet = ( DialogueWave->ContextMappings[i].Context.Targets[j] != NULL );
|
|
|
|
|
if( !bIsValidTargetSet )
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(bIsValidSpeaker && bIsValidTargetSet)
|
|
|
|
|
{
|
|
|
|
|
UniqueSpeakers.AddUnique( DialogueWave->ContextMappings[i].Context.Speaker );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if a refresh is needed.
|
|
|
|
|
bool bNeedsRefresh = false;
|
|
|
|
|
if( OptionsSource.Num() == UniqueSpeakers.Num() )
|
|
|
|
|
{
|
|
|
|
|
for(int32 i = 0; i < UniqueSpeakers.Num(); ++i)
|
|
|
|
|
{
|
|
|
|
|
if( *(OptionsSource[i]) != UniqueSpeakers[i] )
|
|
|
|
|
{
|
|
|
|
|
bNeedsRefresh = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bNeedsRefresh = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Refresh if needed.
|
|
|
|
|
if(bNeedsRefresh)
|
|
|
|
|
{
|
|
|
|
|
OptionsSource.Empty();
|
|
|
|
|
if(DialogueWave)
|
|
|
|
|
{
|
|
|
|
|
for(int32 i = 0; i < UniqueSpeakers.Num(); ++i)
|
|
|
|
|
{
|
|
|
|
|
OptionsSource.Add( MakeShareable( new UDialogueVoice*(UniqueSpeakers[i]) ) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ComboBox->ClearSelection();
|
|
|
|
|
ComboBox->RefreshOptions();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct FSpeakerMatcher
|
|
|
|
|
{
|
|
|
|
|
const UDialogueVoice* Speaker;
|
2014-09-30 11:35:57 -04:00
|
|
|
bool operator()(const FDialogueContextMapping& Mapping) const
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
return Mapping.Context.Speaker == Speaker;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void SSpeakerDropDown::OnSelectionChanged(TSharedPtr<UDialogueVoice*> Speaker, ESelectInfo::Type SelectInfo)
|
|
|
|
|
{
|
|
|
|
|
const TSharedPtr<IPropertyHandle> ContextPropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("Context");
|
|
|
|
|
const TSharedPtr<IPropertyHandle> SpeakerPropertyHandle = ContextPropertyHandle->GetChildHandle("Speaker");
|
|
|
|
|
|
|
|
|
|
UDialogueVoice** SpeakerToChange = NULL;
|
|
|
|
|
{
|
|
|
|
|
TArray<void*> RawData;
|
|
|
|
|
SpeakerPropertyHandle->AccessRawData(RawData);
|
|
|
|
|
SpeakerToChange = reinterpret_cast<UDialogueVoice**>(RawData[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( SpeakerToChange && Speaker.IsValid() )
|
|
|
|
|
{
|
|
|
|
|
SpeakerPropertyHandle->NotifyPreChange();
|
|
|
|
|
*SpeakerToChange = *Speaker;
|
|
|
|
|
SpeakerPropertyHandle->NotifyPostChange();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TSharedRef<SWidget> SSpeakerDropDown::MakeComboButtonItemWidget(TSharedPtr<UDialogueVoice*> Speaker)
|
|
|
|
|
{
|
|
|
|
|
const float ThumbnailSizeX = 64.0f;
|
|
|
|
|
const float ThumbnailSizeY = 64.0f;
|
|
|
|
|
|
|
|
|
|
const TSharedPtr<FAssetThumbnail> AssetThumbnail = MakeShareable( new FAssetThumbnail( *Speaker, ThumbnailSizeX, ThumbnailSizeY, AssetThumbnailPool ) );
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
SNew( SVerticalBox )
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.Padding(2.0f)
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
SNew( SBox )
|
|
|
|
|
.Padding(2.0f)
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
[
|
|
|
|
|
SNew( SBox )
|
|
|
|
|
.WidthOverride( ThumbnailSizeX )
|
|
|
|
|
.HeightOverride( ThumbnailSizeY )
|
|
|
|
|
[
|
|
|
|
|
AssetThumbnail->MakeThumbnailWidget()
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.Padding(2.0f)
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
// Voice Description
|
|
|
|
|
SNew( STextBlock )
|
2015-01-07 09:52:40 -05:00
|
|
|
.Text( ( Speaker.IsValid() && *Speaker ) ? FText::FromString((*Speaker)->GetDesc()) : LOCTEXT("None", "None") )
|
2014-03-14 14:13:41 -04:00
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class STargetSetDropDown : public SCompoundWidget
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
typedef TArray<UDialogueVoice*> FTargetSet;
|
|
|
|
|
|
|
|
|
|
SLATE_BEGIN_ARGS( STargetSetDropDown ) {}
|
|
|
|
|
SLATE_END_ARGS()
|
|
|
|
|
|
|
|
|
|
void Construct( const FArguments& InArgs, const TSharedRef<IPropertyHandle>& InPropertyHandle, const TSharedRef<FAssetThumbnailPool>& InAssetThumbnailPool );
|
2014-06-13 06:14:46 -04:00
|
|
|
virtual void Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime ) override;
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void OnSelectionChanged(TSharedPtr<FTargetSet> TargetSet, ESelectInfo::Type SelectInfo);
|
|
|
|
|
float GetPreferredWidthForWrapping() const;
|
|
|
|
|
TSharedRef<SWidget> MakeComboButtonItemWidget(TSharedPtr<FTargetSet> TargetSet);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
TSharedPtr<IPropertyHandle> DialogueWaveParameterPropertyHandle;
|
|
|
|
|
TSharedPtr<FAssetThumbnailPool> AssetThumbnailPool;
|
|
|
|
|
TSharedPtr< SComboBox< TSharedPtr<FTargetSet> > > ComboBox;
|
|
|
|
|
TArray< TSharedPtr<FTargetSet> > OptionsSource;
|
|
|
|
|
float AllottedWidth;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void STargetSetDropDown::Construct( const FArguments& InArgs, const TSharedRef<IPropertyHandle>& InPropertyHandle, const TSharedRef<FAssetThumbnailPool>& InAssetThumbnailPool )
|
|
|
|
|
{
|
|
|
|
|
DialogueWaveParameterPropertyHandle = InPropertyHandle;
|
|
|
|
|
AssetThumbnailPool = InAssetThumbnailPool;
|
|
|
|
|
|
|
|
|
|
AllottedWidth = 0.0f;
|
|
|
|
|
|
|
|
|
|
const TSharedPtr<IPropertyHandle> ContextPropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("Context") ;
|
|
|
|
|
const TSharedPtr<IPropertyHandle> TargetsPropertyHandle = ContextPropertyHandle->GetChildHandle("Targets") ;
|
|
|
|
|
|
|
|
|
|
TSharedRef<STargetsSummaryWidget> TargetsSummaryWidget =
|
|
|
|
|
SNew( STargetsSummaryWidget, TargetsPropertyHandle.ToSharedRef(), AssetThumbnailPool.ToSharedRef() )
|
|
|
|
|
.IsEditable(false)
|
|
|
|
|
.WrapWidth( this, &STargetSetDropDown::GetPreferredWidthForWrapping);
|
|
|
|
|
|
|
|
|
|
FSlateFontInfo Font = IDetailLayoutBuilder::GetDetailFont();
|
|
|
|
|
|
|
|
|
|
ChildSlot
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
[
|
|
|
|
|
SNew( SVerticalBox )
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.Padding(2.0f)
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
SAssignNew( ComboBox, SComboBox< TSharedPtr<FTargetSet> > )
|
|
|
|
|
.ButtonStyle( FEditorStyle::Get(), "PropertyEditor.AssetComboStyle" )
|
|
|
|
|
.ForegroundColor(FEditorStyle::GetColor("PropertyEditor.AssetName.ColorAndOpacity"))
|
|
|
|
|
.OptionsSource( &OptionsSource )
|
|
|
|
|
.OnGenerateWidget( this, &STargetSetDropDown::MakeComboButtonItemWidget )
|
|
|
|
|
.OnSelectionChanged( this, &STargetSetDropDown::OnSelectionChanged )
|
|
|
|
|
[
|
|
|
|
|
TargetsSummaryWidget
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.Padding( 2.0f )
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
// Voice Description
|
|
|
|
|
SNew( STextBlock )
|
|
|
|
|
.Font( Font )
|
|
|
|
|
.Text( TargetsSummaryWidget, &STargetsSummaryWidget::GetDialogueVoiceDescription )
|
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void STargetSetDropDown::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
|
|
|
|
|
{
|
|
|
|
|
AllottedWidth = AllottedGeometry.Size.X;
|
|
|
|
|
|
|
|
|
|
// Get dialogue wave.
|
|
|
|
|
const TSharedPtr<IPropertyHandle> DialogueWavePropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("DialogueWave");
|
|
|
|
|
const UDialogueWave* DialogueWave = NULL;
|
|
|
|
|
if( DialogueWavePropertyHandle->IsValidHandle() )
|
|
|
|
|
{
|
|
|
|
|
UObject* Object = NULL;
|
|
|
|
|
DialogueWavePropertyHandle->GetValue(Object);
|
|
|
|
|
DialogueWave = Cast<UDialogueWave>(Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get context.
|
|
|
|
|
const TSharedPtr<IPropertyHandle> ContextPropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("Context");
|
|
|
|
|
|
|
|
|
|
// Get speaker.
|
|
|
|
|
const TSharedPtr<IPropertyHandle> SpeakerPropertyHandle = ContextPropertyHandle->GetChildHandle("Speaker");
|
|
|
|
|
const UDialogueVoice* Speaker = NULL;
|
|
|
|
|
{
|
|
|
|
|
UObject* Object = NULL;
|
|
|
|
|
SpeakerPropertyHandle->GetValue(Object);
|
|
|
|
|
Speaker = Cast<UDialogueVoice>(Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get target set.
|
|
|
|
|
const TSharedPtr<IPropertyHandle> TargetsPropertyHandle = ContextPropertyHandle->GetChildHandle("Targets");
|
|
|
|
|
FTargetSet* TargetSet = NULL;
|
|
|
|
|
{
|
|
|
|
|
TArray<void*> RawData;
|
|
|
|
|
TargetsPropertyHandle->AccessRawData(RawData);
|
|
|
|
|
TargetSet = reinterpret_cast<FTargetSet*>(RawData[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Gather unique target set options.
|
|
|
|
|
TArray<FTargetSet> UniqueTargetSets;
|
|
|
|
|
if( DialogueWave && Speaker )
|
|
|
|
|
{
|
|
|
|
|
for(int32 i = 0; i < DialogueWave->ContextMappings.Num(); ++i)
|
|
|
|
|
{
|
|
|
|
|
if( DialogueWave->ContextMappings[i].Context.Speaker == Speaker )
|
|
|
|
|
{
|
|
|
|
|
bool bIsValidTargetSet = true;
|
|
|
|
|
|
|
|
|
|
for(int32 j = 0; j < DialogueWave->ContextMappings[i].Context.Targets.Num(); ++j)
|
|
|
|
|
{
|
|
|
|
|
bIsValidTargetSet = ( DialogueWave->ContextMappings[i].Context.Targets[j] != NULL );
|
|
|
|
|
if( !bIsValidTargetSet )
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( bIsValidTargetSet )
|
|
|
|
|
{
|
|
|
|
|
UniqueTargetSets.AddUnique( DialogueWave->ContextMappings[i].Context.Targets );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if a refresh is needed.
|
|
|
|
|
bool bNeedsRefresh = false;
|
|
|
|
|
if( OptionsSource.Num() == UniqueTargetSets.Num() )
|
|
|
|
|
{
|
|
|
|
|
for(int32 i = 0; i < UniqueTargetSets.Num(); ++i)
|
|
|
|
|
{
|
|
|
|
|
if( *(OptionsSource[i]) != UniqueTargetSets[i] )
|
|
|
|
|
{
|
|
|
|
|
bNeedsRefresh = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bNeedsRefresh = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Refresh if needed.
|
|
|
|
|
if(bNeedsRefresh)
|
|
|
|
|
{
|
|
|
|
|
OptionsSource.Empty();
|
|
|
|
|
if(DialogueWave)
|
|
|
|
|
{
|
|
|
|
|
for(int32 i = 0; i < UniqueTargetSets.Num(); ++i)
|
|
|
|
|
{
|
|
|
|
|
OptionsSource.Add( MakeShareable( new FTargetSet(UniqueTargetSets[i]) ) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ComboBox->ClearSelection();
|
|
|
|
|
ComboBox->RefreshOptions();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void STargetSetDropDown::OnSelectionChanged(TSharedPtr<FTargetSet> TargetSet, ESelectInfo::Type SelectInfo)
|
|
|
|
|
{
|
|
|
|
|
const TSharedPtr<IPropertyHandle> ContextPropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("Context");
|
|
|
|
|
const TSharedPtr<IPropertyHandle> TargetsPropertyHandle = ContextPropertyHandle->GetChildHandle("Targets");
|
|
|
|
|
|
|
|
|
|
FTargetSet* TargetSetToChange = NULL;
|
|
|
|
|
{
|
|
|
|
|
TArray<void*> RawData;
|
|
|
|
|
TargetsPropertyHandle->AccessRawData(RawData);
|
|
|
|
|
TargetSetToChange = reinterpret_cast<FTargetSet*>(RawData[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( TargetSet.IsValid() )
|
|
|
|
|
{
|
|
|
|
|
TargetsPropertyHandle->NotifyPreChange();
|
|
|
|
|
*TargetSetToChange = *TargetSet;
|
|
|
|
|
TargetsPropertyHandle->NotifyPostChange();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float STargetSetDropDown::GetPreferredWidthForWrapping() const
|
|
|
|
|
{
|
|
|
|
|
return AllottedWidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
|
|
|
TSharedRef<SWidget> STargetSetDropDown::MakeComboButtonItemWidget(TSharedPtr<FTargetSet> TargetSet)
|
|
|
|
|
{
|
|
|
|
|
TSharedPtr<SWidget> Result;
|
|
|
|
|
|
|
|
|
|
const float ThumbnailSizeX = 64.0f;
|
|
|
|
|
const float ThumbnailSizeY = 64.0f;
|
|
|
|
|
|
|
|
|
|
FSlateFontInfo Font = IDetailLayoutBuilder::GetDetailFont();
|
|
|
|
|
|
|
|
|
|
if( TargetSet->Num() > 1 )
|
|
|
|
|
{
|
|
|
|
|
const TSharedRef<SWrapBox> WrapBox =
|
|
|
|
|
SNew( SWrapBox )
|
|
|
|
|
.PreferredWidth( this, &STargetSetDropDown::GetPreferredWidthForWrapping );
|
|
|
|
|
|
|
|
|
|
for(int32 i = 0; i < TargetSet->Num(); ++i)
|
|
|
|
|
{
|
|
|
|
|
const TSharedPtr<FAssetThumbnail> AssetThumbnail = MakeShareable( new FAssetThumbnail( (*TargetSet)[i], ThumbnailSizeX, ThumbnailSizeY, AssetThumbnailPool ) );
|
|
|
|
|
|
|
|
|
|
WrapBox->AddSlot()
|
|
|
|
|
.Padding(2.0f)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
[
|
|
|
|
|
SNew( SBox )
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
[
|
|
|
|
|
SNew( SBox )
|
|
|
|
|
.WidthOverride( ThumbnailSizeX )
|
|
|
|
|
.HeightOverride( ThumbnailSizeY )
|
|
|
|
|
[
|
|
|
|
|
AssetThumbnail->MakeThumbnailWidget()
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Result =
|
|
|
|
|
SNew( SVerticalBox )
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.Padding(2.0f)
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
WrapBox
|
|
|
|
|
]
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.Padding( 2.0f )
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
// Voice Description
|
|
|
|
|
SNew( STextBlock )
|
|
|
|
|
.Font( Font )
|
|
|
|
|
.Text( LOCTEXT("Multiple", "Multiple") )
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
else if( TargetSet->Num() == 1 )
|
|
|
|
|
{
|
|
|
|
|
UDialogueVoice* Target = (*TargetSet)[0];
|
|
|
|
|
const TSharedPtr<FAssetThumbnail> AssetThumbnail = MakeShareable( new FAssetThumbnail( Target, ThumbnailSizeX, ThumbnailSizeY, AssetThumbnailPool ) );
|
|
|
|
|
|
|
|
|
|
SAssignNew( Result, SVerticalBox )
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.Padding(2.0f)
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
SNew( SBox )
|
|
|
|
|
.Padding(2.0f)
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
[
|
|
|
|
|
SNew( SBox )
|
|
|
|
|
.WidthOverride( ThumbnailSizeX )
|
|
|
|
|
.HeightOverride( ThumbnailSizeY )
|
|
|
|
|
[
|
|
|
|
|
AssetThumbnail->MakeThumbnailWidget()
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.Padding(2.0f)
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
// Voice Description
|
|
|
|
|
SNew( STextBlock )
|
|
|
|
|
.Font( Font )
|
2015-01-07 09:52:40 -05:00
|
|
|
.Text( Target ? FText::FromString(Target->GetDesc()) : LOCTEXT("None", "None") )
|
2014-03-14 14:13:41 -04:00
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SAssignNew( Result, SVerticalBox )
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.Padding(2.0f)
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
SNew( SBox )
|
|
|
|
|
.WidthOverride( ThumbnailSizeX )
|
|
|
|
|
.HeightOverride( ThumbnailSizeY )
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
]
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.Padding(2.0f)
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
// Voice Description
|
|
|
|
|
SNew( STextBlock )
|
|
|
|
|
.Font( Font )
|
|
|
|
|
.Text( LOCTEXT( "NoTargets", "No One" ) )
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Result.ToSharedRef();
|
|
|
|
|
}
|
|
|
|
|
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
|
|
|
|
|
|
|
|
class SValidatedDialogueContextHeaderWidget : public SCompoundWidget
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
SLATE_BEGIN_ARGS( SValidatedDialogueContextHeaderWidget ) {}
|
|
|
|
|
SLATE_END_ARGS()
|
|
|
|
|
|
|
|
|
|
void Construct( const FArguments& InArgs, const TSharedRef<IPropertyHandle>& InPropertyHandle, const TSharedRef<FAssetThumbnailPool>& InAssetThumbnailPool );
|
---- Merging with SlateDev branch ----
Introduces the concept of "Active Ticking" to allow Slate to go to sleep when there is no need to update the UI.
While asleep, Slate will skip the Tick & Paint pass for that frame entirely.
- There are TWO ways to "wake" Slate and cause a Tick/Paint pass:
1. Provide some sort of input (mouse movement, clicks, and key presses). Slate will always tick when the user is active.
- Therefore, if the logic in a given widget's Tick is only relevant in response to user action, there is no need to register an active tick.
2. Register an Active Tick. Currently this is an all-or-nothing situation, so if a single active tick needs to execute, all of Slate will be ticked.
- The purpose of an Active Tick is to allow a widget to "drive" Slate and guarantee a Tick/Paint pass in the absence of any user action.
- Examples include animation, async operations that update periodically, progress updates, loading bars, etc.
- An empty active tick is registered for viewports when they are real-time, so game project widgets are unaffected by this change and should continue to work as before.
- An Active Tick is registered by creating an FWidgetActiveTickDelegate and passing it to SWidget::RegisterActiveTick()
- There are THREE ways to unregister an active tick:
1. Return EActiveTickReturnType::StopTicking from the active tick function
2. Pass the FActiveTickHandle returned by RegisterActiveTick() to SWidget::UnregisterActiveTick()
3. Destroy the widget responsible for the active tick
- Sleeping is currently disabled, can be enabled with Slate.AllowSlateToSleep cvar
- There is currently a little buffer time during which Slate continues to tick following any input. Long-term, this is planned to be removed.
- The duration of the buffer can be adjusted using Slate.SleepBufferPostInput cvar (defaults to 1.0f)
- The FCurveSequence API has been updated to work with the active tick system
- Playing a curve sequence now requires that you pass the widget being animated by the sequence
- The active tick will automatically be registered on behalf of the widget and unregister when the sequence is complete
- GetLerpLooping() has been removed. Instead, pass true as the second param to Play() to indicate that the animation will loop. This causes the active tick to be registered indefinitely until paused or jumped to the start/end.
[CL 2391669 by Dan Hertzka in Main branch]
2014-12-17 16:07:57 -05:00
|
|
|
virtual void Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime ) override;
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
bool IsDialogueWaveValid() const;
|
|
|
|
|
bool IsSpeakerValid() const;
|
|
|
|
|
bool IsTargetSetValid() const;
|
|
|
|
|
|
|
|
|
|
bool ShouldSpeakerDropDownBeEnabled() const;
|
|
|
|
|
EVisibility GetSpeakerErrorVisibility() const;
|
|
|
|
|
|
|
|
|
|
bool ShouldTargetsDropDownBeEnabled() const;
|
|
|
|
|
EVisibility GetTargetsErrorVisibility() const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const UDialogueWave* CurrentDialogueWave;
|
|
|
|
|
TSharedPtr<IPropertyHandle> DialogueWaveParameterPropertyHandle;
|
|
|
|
|
TSharedPtr<SErrorHint> ContextErrorHint;
|
|
|
|
|
TSharedPtr<SErrorHint> SpeakerErrorHint;
|
|
|
|
|
TSharedPtr<SErrorText> SpeakerErrorText;
|
|
|
|
|
TSharedPtr<SErrorHint> TargetsErrorHint;
|
|
|
|
|
TSharedPtr<SErrorText> TargetsErrorText;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
|
|
|
void SValidatedDialogueContextHeaderWidget::Construct( const FArguments& InArgs, const TSharedRef<IPropertyHandle>& InPropertyHandle, const TSharedRef<FAssetThumbnailPool>& InAssetThumbnailPool )
|
|
|
|
|
{
|
|
|
|
|
DialogueWaveParameterPropertyHandle = InPropertyHandle;
|
|
|
|
|
|
|
|
|
|
const TSharedPtr<IPropertyHandle> DialogueWavePropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("DialogueWave");
|
|
|
|
|
CurrentDialogueWave = NULL;
|
|
|
|
|
{
|
|
|
|
|
UObject* Object = NULL;
|
|
|
|
|
DialogueWavePropertyHandle->GetValue(Object);
|
|
|
|
|
CurrentDialogueWave = Cast<UDialogueWave>(Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const TSharedPtr<IPropertyHandle> ContextPropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("Context");
|
|
|
|
|
if( ContextPropertyHandle->IsValidHandle() )
|
|
|
|
|
{
|
|
|
|
|
const TSharedPtr<IPropertyHandle> SpeakerPropertyHandle = ContextPropertyHandle->GetChildHandle("Speaker");
|
|
|
|
|
const TSharedPtr<IPropertyHandle> TargetsPropertyHandle = ContextPropertyHandle->GetChildHandle("Targets");
|
|
|
|
|
|
|
|
|
|
ChildSlot
|
|
|
|
|
[
|
|
|
|
|
SNew( SBorder )
|
|
|
|
|
.BorderImage( FEditorStyle::GetBrush("DialogueWaveDetails.HeaderBorder") )
|
|
|
|
|
[
|
|
|
|
|
SNew( SVerticalBox )
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
SNew( SHorizontalBox )
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.HAlign(HAlign_Right)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
.FillWidth(1.0f)
|
|
|
|
|
[
|
|
|
|
|
SAssignNew( ContextErrorHint, SErrorHint )
|
|
|
|
|
]
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.AutoWidth()
|
|
|
|
|
[
|
|
|
|
|
ContextPropertyHandle->CreatePropertyNameWidget()
|
|
|
|
|
]
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.FillWidth(1.0f)
|
|
|
|
|
[
|
|
|
|
|
SNullWidget::NullWidget
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.Padding( FMargin( 4.0f, 2.0f, 4.0f, 4.0f ) )
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
SNew( SHorizontalBox )
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.FillWidth(1.0f)
|
|
|
|
|
[
|
|
|
|
|
SNew( SVerticalBox )
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
SNew( SHorizontalBox )
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.HAlign(HAlign_Right)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
.FillWidth(1.0f)
|
|
|
|
|
[
|
|
|
|
|
SAssignNew( SpeakerErrorHint, SErrorHint )
|
|
|
|
|
]
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.AutoWidth()
|
|
|
|
|
[
|
|
|
|
|
SpeakerPropertyHandle->CreatePropertyNameWidget()
|
|
|
|
|
]
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.FillWidth(1.0f)
|
|
|
|
|
[
|
|
|
|
|
SNullWidget::NullWidget
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.HAlign(HAlign_Fill)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
.FillHeight(1.0f)
|
|
|
|
|
[
|
|
|
|
|
SNew( SOverlay )
|
|
|
|
|
+SOverlay::Slot()
|
|
|
|
|
[
|
|
|
|
|
SNew( SSpeakerDropDown, DialogueWaveParameterPropertyHandle.ToSharedRef(), InAssetThumbnailPool )
|
|
|
|
|
.IsEnabled( this, &SValidatedDialogueContextHeaderWidget::ShouldSpeakerDropDownBeEnabled )
|
|
|
|
|
]
|
|
|
|
|
+SOverlay::Slot()
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
[
|
|
|
|
|
SNew( SBox )
|
|
|
|
|
.Visibility( this, &SValidatedDialogueContextHeaderWidget::GetSpeakerErrorVisibility )
|
|
|
|
|
[
|
|
|
|
|
SAssignNew( SpeakerErrorText, SErrorText )
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
.Padding(4.0f)
|
|
|
|
|
.AutoWidth()
|
|
|
|
|
[
|
|
|
|
|
SNew( SImage )
|
|
|
|
|
.Image( FEditorStyle::GetBrush("DialogueWaveDetails.SpeakerToTarget") )
|
|
|
|
|
.ColorAndOpacity( FSlateColor::UseForeground() )
|
|
|
|
|
]
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.FillWidth(1.0f)
|
|
|
|
|
[
|
|
|
|
|
SNew( SVerticalBox )
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
SNew( SHorizontalBox )
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.HAlign(HAlign_Right)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
.FillWidth(1.0f)
|
|
|
|
|
[
|
|
|
|
|
SAssignNew( TargetsErrorHint, SErrorHint )
|
|
|
|
|
]
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.AutoWidth()
|
|
|
|
|
[
|
2014-12-01 11:19:41 -05:00
|
|
|
TargetsPropertyHandle->CreatePropertyNameWidget( LOCTEXT("DirectedAt", "Directed At") )
|
2014-03-14 14:13:41 -04:00
|
|
|
]
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.FillWidth(1.0f)
|
|
|
|
|
[
|
|
|
|
|
SNullWidget::NullWidget
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.HAlign(HAlign_Fill)
|
|
|
|
|
.FillHeight(1.0f)
|
|
|
|
|
[
|
|
|
|
|
SNew( SOverlay )
|
|
|
|
|
+SOverlay::Slot()
|
|
|
|
|
[
|
|
|
|
|
SNew( STargetSetDropDown, DialogueWaveParameterPropertyHandle.ToSharedRef(), InAssetThumbnailPool )
|
|
|
|
|
.IsEnabled( this, &SValidatedDialogueContextHeaderWidget::ShouldTargetsDropDownBeEnabled )
|
|
|
|
|
]
|
|
|
|
|
+SOverlay::Slot()
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
[
|
|
|
|
|
SNew( SBox )
|
|
|
|
|
.Visibility( this, &SValidatedDialogueContextHeaderWidget::GetTargetsErrorVisibility )
|
|
|
|
|
[
|
|
|
|
|
SAssignNew( TargetsErrorText, SErrorText )
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|
---- Merging with SlateDev branch ----
Introduces the concept of "Active Ticking" to allow Slate to go to sleep when there is no need to update the UI.
While asleep, Slate will skip the Tick & Paint pass for that frame entirely.
- There are TWO ways to "wake" Slate and cause a Tick/Paint pass:
1. Provide some sort of input (mouse movement, clicks, and key presses). Slate will always tick when the user is active.
- Therefore, if the logic in a given widget's Tick is only relevant in response to user action, there is no need to register an active tick.
2. Register an Active Tick. Currently this is an all-or-nothing situation, so if a single active tick needs to execute, all of Slate will be ticked.
- The purpose of an Active Tick is to allow a widget to "drive" Slate and guarantee a Tick/Paint pass in the absence of any user action.
- Examples include animation, async operations that update periodically, progress updates, loading bars, etc.
- An empty active tick is registered for viewports when they are real-time, so game project widgets are unaffected by this change and should continue to work as before.
- An Active Tick is registered by creating an FWidgetActiveTickDelegate and passing it to SWidget::RegisterActiveTick()
- There are THREE ways to unregister an active tick:
1. Return EActiveTickReturnType::StopTicking from the active tick function
2. Pass the FActiveTickHandle returned by RegisterActiveTick() to SWidget::UnregisterActiveTick()
3. Destroy the widget responsible for the active tick
- Sleeping is currently disabled, can be enabled with Slate.AllowSlateToSleep cvar
- There is currently a little buffer time during which Slate continues to tick following any input. Long-term, this is planned to be removed.
- The duration of the buffer can be adjusted using Slate.SleepBufferPostInput cvar (defaults to 1.0f)
- The FCurveSequence API has been updated to work with the active tick system
- Playing a curve sequence now requires that you pass the widget being animated by the sequence
- The active tick will automatically be registered on behalf of the widget and unregister when the sequence is complete
- GetLerpLooping() has been removed. Instead, pass true as the second param to Play() to indicate that the animation will loop. This causes the active tick to be registered indefinitely until paused or jumped to the start/end.
[CL 2391669 by Dan Hertzka in Main branch]
2014-12-17 16:07:57 -05:00
|
|
|
void SValidatedDialogueContextHeaderWidget::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
if( DialogueWaveParameterPropertyHandle.IsValid() && DialogueWaveParameterPropertyHandle->IsValidHandle() )
|
|
|
|
|
{
|
|
|
|
|
// Get dialogue wave.
|
|
|
|
|
const TSharedPtr<IPropertyHandle> DialogueWavePropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("DialogueWave");
|
|
|
|
|
const UDialogueWave* DialogueWave = NULL;
|
|
|
|
|
if( DialogueWavePropertyHandle.IsValid() && DialogueWavePropertyHandle->IsValidHandle() )
|
|
|
|
|
{
|
|
|
|
|
UObject* Object = NULL;
|
|
|
|
|
DialogueWavePropertyHandle->GetValue(Object);
|
|
|
|
|
DialogueWave = Cast<UDialogueWave>(Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get context.
|
|
|
|
|
const TSharedPtr<IPropertyHandle> ContextPropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("Context");
|
|
|
|
|
|
|
|
|
|
// Get speaker.
|
|
|
|
|
const TSharedPtr<IPropertyHandle> SpeakerPropertyHandle = ContextPropertyHandle->GetChildHandle("Speaker");
|
|
|
|
|
UDialogueVoice* Speaker = NULL;
|
|
|
|
|
if( SpeakerPropertyHandle.IsValid() && SpeakerPropertyHandle->IsValidHandle())
|
|
|
|
|
{
|
|
|
|
|
UObject* Object = NULL;
|
|
|
|
|
SpeakerPropertyHandle->GetValue(Object);
|
|
|
|
|
Speaker = Cast<UDialogueVoice>(Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get target set.
|
|
|
|
|
const TSharedPtr<IPropertyHandle> TargetsPropertyHandle = ContextPropertyHandle->GetChildHandle("Targets");
|
|
|
|
|
STargetSetDropDown::FTargetSet* TargetSet = NULL;
|
|
|
|
|
if( TargetsPropertyHandle.IsValid() && TargetsPropertyHandle->IsValidHandle())
|
|
|
|
|
{
|
|
|
|
|
TArray<void*> RawData;
|
|
|
|
|
TargetsPropertyHandle->AccessRawData(RawData);
|
|
|
|
|
TargetSet = reinterpret_cast<STargetSetDropDown::FTargetSet*>(RawData[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool bDidDialogueWaveChange = (CurrentDialogueWave != DialogueWave);
|
|
|
|
|
if( bDidDialogueWaveChange )
|
|
|
|
|
{
|
|
|
|
|
CurrentDialogueWave = DialogueWave;
|
|
|
|
|
|
|
|
|
|
// Check if the speaker needs to be reset.
|
|
|
|
|
bool bSpeakerNeedsReset = true;
|
|
|
|
|
bool bTargetSetNeedsReset = true;
|
|
|
|
|
if( DialogueWave )
|
|
|
|
|
{
|
|
|
|
|
for(int32 i = 0; i < DialogueWave->ContextMappings.Num(); ++i)
|
|
|
|
|
{
|
|
|
|
|
if( bSpeakerNeedsReset )
|
|
|
|
|
{
|
|
|
|
|
bSpeakerNeedsReset = ( DialogueWave->ContextMappings[i].Context.Speaker != Speaker );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( bTargetSetNeedsReset && TargetSet )
|
|
|
|
|
{
|
|
|
|
|
bTargetSetNeedsReset = ( DialogueWave->ContextMappings[i].Context.Targets != *TargetSet );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !bSpeakerNeedsReset && !bTargetSetNeedsReset)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Don't try resets if there are no valid contexts.
|
|
|
|
|
if( DialogueWave && DialogueWave->ContextMappings.Num() > 0)
|
|
|
|
|
{
|
|
|
|
|
// Speaker reset if needed and possible.
|
|
|
|
|
if( bSpeakerNeedsReset && SpeakerPropertyHandle.IsValid() && SpeakerPropertyHandle->IsValidHandle() )
|
|
|
|
|
{
|
|
|
|
|
const UObject* Object = DialogueWave->ContextMappings[0].Context.Speaker;
|
|
|
|
|
SpeakerPropertyHandle->SetValue( Object );
|
|
|
|
|
}
|
|
|
|
|
// Target set reset if needed.
|
|
|
|
|
if(bTargetSetNeedsReset)
|
|
|
|
|
{
|
|
|
|
|
// Reset if possible.
|
|
|
|
|
if( TargetSet && TargetsPropertyHandle.IsValid() && TargetsPropertyHandle->IsValidHandle() )
|
|
|
|
|
{
|
|
|
|
|
TargetsPropertyHandle->NotifyPreChange();
|
|
|
|
|
*TargetSet = DialogueWave->ContextMappings[0].Context.Targets;
|
|
|
|
|
TargetsPropertyHandle->NotifyPostChange();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !IsDialogueWaveValid() )
|
|
|
|
|
{
|
|
|
|
|
if( ContextErrorHint.IsValid() ) { ContextErrorHint->SetError( LOCTEXT("InvalidDialogueWaveError", "Invalid dialogue wave.") ); }
|
|
|
|
|
|
|
|
|
|
if( SpeakerErrorHint.IsValid() ) { SpeakerErrorHint->SetError( FText::GetEmpty() ); }
|
|
|
|
|
if( SpeakerErrorText.IsValid() ) { SpeakerErrorText->SetError( LOCTEXT("SelectDialogueWaveError", "Select a valid dialogue wave.") ); }
|
|
|
|
|
if( TargetsErrorHint.IsValid() ) { TargetsErrorHint->SetError( FText::GetEmpty() ); }
|
|
|
|
|
if( TargetsErrorText.IsValid() ) { TargetsErrorText->SetError( LOCTEXT("SelectDialogueWaveError", "Select a valid dialogue wave.") ); }
|
|
|
|
|
}
|
|
|
|
|
else if( !IsSpeakerValid() )
|
|
|
|
|
{
|
|
|
|
|
if( ContextErrorHint.IsValid() ) { ContextErrorHint->SetError( FText::GetEmpty() ); }
|
|
|
|
|
|
|
|
|
|
if( SpeakerErrorHint.IsValid() ) { SpeakerErrorHint->SetError( LOCTEXT("InvalidSpeakerError", "Invalid speaker for dialogue wave.") ); }
|
|
|
|
|
if( SpeakerErrorText.IsValid() ) { SpeakerErrorText->SetError( FText::GetEmpty() ); }
|
|
|
|
|
if( TargetsErrorHint.IsValid() ) { TargetsErrorHint->SetError( FText::GetEmpty() ); }
|
|
|
|
|
if( TargetsErrorText.IsValid() ) { TargetsErrorText->SetError( LOCTEXT("SelectSpeakerError", "Select a valid speaker.") ); }
|
|
|
|
|
}
|
|
|
|
|
else if( !IsTargetSetValid() )
|
|
|
|
|
{
|
|
|
|
|
if( ContextErrorHint.IsValid() ) { ContextErrorHint->SetError( FText::GetEmpty() ); }
|
|
|
|
|
|
|
|
|
|
if( SpeakerErrorHint.IsValid() ) { SpeakerErrorHint->SetError( FText::GetEmpty() ); }
|
|
|
|
|
if( SpeakerErrorText.IsValid() ) { SpeakerErrorText->SetError( FText::GetEmpty() ); }
|
|
|
|
|
if( TargetsErrorHint.IsValid() ) { TargetsErrorHint->SetError( LOCTEXT("SelectTargetsError", "Select a valid target set.") ); }
|
|
|
|
|
if( TargetsErrorText.IsValid() ) { TargetsErrorText->SetError( FText::GetEmpty() ); }
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if( ContextErrorHint.IsValid() ) { ContextErrorHint->SetError( FText::GetEmpty() ); }
|
|
|
|
|
|
|
|
|
|
if( SpeakerErrorHint.IsValid() ) { SpeakerErrorHint->SetError( FText::GetEmpty() ); }
|
|
|
|
|
if( SpeakerErrorText.IsValid() ) { SpeakerErrorText->SetError( FText::GetEmpty() ); }
|
|
|
|
|
if( TargetsErrorHint.IsValid() ) { TargetsErrorHint->SetError( FText::GetEmpty() ); }
|
|
|
|
|
if( TargetsErrorText.IsValid() ) { TargetsErrorText->SetError( FText::GetEmpty() ); }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SValidatedDialogueContextHeaderWidget::IsDialogueWaveValid() const
|
|
|
|
|
{
|
|
|
|
|
const UDialogueWave* DialogueWave = NULL;
|
|
|
|
|
|
|
|
|
|
const TSharedPtr<IPropertyHandle> DialogueWavePropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("DialogueWave");
|
|
|
|
|
if( DialogueWavePropertyHandle->IsValidHandle() )
|
|
|
|
|
{
|
|
|
|
|
UObject* Object = NULL;
|
|
|
|
|
DialogueWavePropertyHandle->GetValue(Object);
|
|
|
|
|
DialogueWave = Cast<UDialogueWave>(Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return DialogueWave != NULL && DialogueWave->ContextMappings.Num() > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SValidatedDialogueContextHeaderWidget::IsSpeakerValid() const
|
|
|
|
|
{
|
|
|
|
|
const TSharedPtr<IPropertyHandle> DialogueWavePropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("DialogueWave");
|
|
|
|
|
const UDialogueWave* DialogueWave = NULL;
|
|
|
|
|
{
|
|
|
|
|
UObject* Object = NULL;
|
|
|
|
|
DialogueWavePropertyHandle->GetValue(Object);
|
|
|
|
|
DialogueWave = Cast<UDialogueWave>(Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const TSharedPtr<IPropertyHandle> ContextPropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("Context");
|
|
|
|
|
const TSharedPtr<IPropertyHandle> SpeakerPropertyHandle = ContextPropertyHandle->GetChildHandle("Speaker");
|
|
|
|
|
const UDialogueVoice* Speaker = NULL;
|
|
|
|
|
{
|
|
|
|
|
UObject* Object = NULL;
|
|
|
|
|
SpeakerPropertyHandle->GetValue(Object);
|
|
|
|
|
Speaker = Cast<UDialogueVoice>(Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool bSpeakerIsValid = false;
|
|
|
|
|
if( DialogueWave )
|
|
|
|
|
{
|
|
|
|
|
FSpeakerMatcher SpeakerMatcher = { Speaker };
|
2014-09-30 11:35:57 -04:00
|
|
|
if (DialogueWave->ContextMappings.IndexOfByPredicate(SpeakerMatcher) != INDEX_NONE)
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
bSpeakerIsValid = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bSpeakerIsValid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SValidatedDialogueContextHeaderWidget::IsTargetSetValid() const
|
|
|
|
|
{
|
|
|
|
|
const TSharedPtr<IPropertyHandle> DialogueWavePropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("DialogueWave");
|
|
|
|
|
const UDialogueWave* DialogueWave = NULL;
|
|
|
|
|
{
|
|
|
|
|
UObject* Object = NULL;
|
|
|
|
|
DialogueWavePropertyHandle->GetValue(Object);
|
|
|
|
|
DialogueWave = Cast<UDialogueWave>(Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const TSharedPtr<IPropertyHandle> ContextPropertyHandle = DialogueWaveParameterPropertyHandle->GetChildHandle("Context");
|
|
|
|
|
const FDialogueContext* DialogueContext = NULL;
|
|
|
|
|
{
|
|
|
|
|
TArray<void*> RawData;
|
|
|
|
|
ContextPropertyHandle->AccessRawData(RawData);
|
|
|
|
|
DialogueContext = reinterpret_cast<FDialogueContext*>(RawData[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return DialogueWave && DialogueContext && DialogueWave->SupportsContext(*DialogueContext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SValidatedDialogueContextHeaderWidget::ShouldSpeakerDropDownBeEnabled() const
|
|
|
|
|
{
|
|
|
|
|
return IsDialogueWaveValid();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EVisibility SValidatedDialogueContextHeaderWidget::GetSpeakerErrorVisibility() const
|
|
|
|
|
{
|
|
|
|
|
return SpeakerErrorText.IsValid() && SpeakerErrorText->HasError() ? EVisibility::Visible : EVisibility::Collapsed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SValidatedDialogueContextHeaderWidget::ShouldTargetsDropDownBeEnabled() const
|
|
|
|
|
{
|
|
|
|
|
return IsSpeakerValid();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EVisibility SValidatedDialogueContextHeaderWidget::GetTargetsErrorVisibility() const
|
|
|
|
|
{
|
|
|
|
|
return TargetsErrorText.IsValid() && TargetsErrorText->HasError() ? EVisibility::Visible : EVisibility::Collapsed;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-04 10:16:14 -04:00
|
|
|
TSharedRef<IPropertyTypeCustomization> FDialogueWaveParameterStructCustomization::MakeInstance()
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
return MakeShareable( new FDialogueWaveParameterStructCustomization );
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-04 11:16:24 -04:00
|
|
|
void FDialogueWaveParameterStructCustomization::CustomizeHeader( TSharedRef<IPropertyHandle> StructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils )
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-04 11:16:24 -04:00
|
|
|
void FDialogueWaveParameterStructCustomization::CustomizeChildren( TSharedRef<IPropertyHandle> StructPropertyHandle, class IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils )
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
if( StructPropertyHandle->IsValidHandle() )
|
|
|
|
|
{
|
|
|
|
|
const TSharedPtr<IPropertyHandle> DialogueWavePropertyHandle = StructPropertyHandle->GetChildHandle("DialogueWave");
|
|
|
|
|
ChildBuilder.AddChildProperty(DialogueWavePropertyHandle.ToSharedRef());
|
|
|
|
|
|
|
|
|
|
const TSharedPtr<IPropertyHandle> ContextPropertyHandle = StructPropertyHandle->GetChildHandle("Context");
|
|
|
|
|
ChildBuilder.AddChildContent( ContextPropertyHandle->GetPropertyDisplayName() )
|
|
|
|
|
[
|
|
|
|
|
SNew( SValidatedDialogueContextHeaderWidget, StructPropertyHandle, StructCustomizationUtils.GetThumbnailPool().ToSharedRef() )
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|