Files
UnrealEngineUWP/Engine/Source/Editor/EditorWidgets/Private/SObjectNameEditableTextBox.cpp

368 lines
12 KiB
C++
Raw Normal View History

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "EditorWidgetsPrivatePCH.h"
#include "ScopedTransaction.h"
const float SObjectNameEditableTextBox::HighlightRectLeftOffset = 0.0f;
const float SObjectNameEditableTextBox::HighlightRectRightOffset = 0.0f;
const float SObjectNameEditableTextBox::HighlightTargetSpringConstant = 25.0f;
const float SObjectNameEditableTextBox::HighlightTargetEffectDuration = 0.5f;
const float SObjectNameEditableTextBox::HighlightTargetOpacity = 0.8f;
const float SObjectNameEditableTextBox::CommittingAnimOffsetPercent = 0.2f;
#define LOCTEXT_NAMESPACE "EditorWidgets"
void SObjectNameEditableTextBox::Construct( const FArguments& InArgs )
{
---- 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
LastCommittedTime = 0.0;
bUpdateHighlightSpring = false;
Objects = InArgs._Objects;
ChildSlot
[
SAssignNew(TextBox, SEditableTextBox)
.Text( this, &SObjectNameEditableTextBox::GetNameText )
.ToolTipText( this, &SObjectNameEditableTextBox::GetNameTooltipText )
.Visibility( this, &SObjectNameEditableTextBox::GetNameVisibility )
.HintText( this, &SObjectNameEditableTextBox::GetNameHintText )
.OnTextCommitted( this, &SObjectNameEditableTextBox::OnNameTextCommitted )
.IsReadOnly( this, &SObjectNameEditableTextBox::CannotEditNameText )
.SelectAllTextWhenFocused( this, &SObjectNameEditableTextBox::CanEditNameText )
.OnTextChanged(this, &SObjectNameEditableTextBox::OnTextChanged )
.RevertTextOnEscape( true )
];
}
EActiveTimerReturnType SObjectNameEditableTextBox::UpdateHighlightSpringState( double InCurrentTime, float InDeltaTime )
---- 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
{
if ( (float)(InCurrentTime - LastCommittedTime) <= HighlightTargetEffectDuration )
{
bUpdateHighlightSpring = true;
}
else
{
bUpdateHighlightSpring = false;
}
return bUpdateHighlightSpring ? EActiveTimerReturnType::Continue : EActiveTimerReturnType::Stop;
---- 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 SObjectNameEditableTextBox::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
{
---- 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
const bool bShouldAppearFocused = HasKeyboardFocus();
---- 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
if ( bUpdateHighlightSpring || bShouldAppearFocused )
{
---- 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
// Update highlight 'target' effect
const float HighlightLeftX = HighlightRectLeftOffset;
const float HighlightRightX = HighlightRectRightOffset + AllottedGeometry.Size.X;
HighlightTargetLeftSpring.SetTarget( HighlightLeftX );
HighlightTargetRightSpring.SetTarget( HighlightRightX );
---- 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
HighlightTargetLeftSpring.Tick( InDeltaTime );
HighlightTargetRightSpring.Tick( InDeltaTime );
}
}
int32 SObjectNameEditableTextBox::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const
{
int32 StartLayer = SCompoundWidget::OnPaint( Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled );
const int32 TextLayer = 1;
// See if a disabled effect should be used
bool bEnabled = ShouldBeEnabled( bParentEnabled );
ESlateDrawEffect::Type DrawEffects = (bEnabled) ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;
const double CurrentTime = FSlateApplication::Get().GetCurrentTime();
// Draw highlight targeting effect
const float TimeSinceHighlightInteraction = (float)( CurrentTime - LastCommittedTime );
if( TimeSinceHighlightInteraction <= HighlightTargetEffectDuration )
{
// Compute animation progress
float EffectAlpha = FMath::Clamp( TimeSinceHighlightInteraction / HighlightTargetEffectDuration, 0.0f, 1.0f );
EffectAlpha = 1.0f - EffectAlpha * EffectAlpha; // Inverse square falloff (looks nicer!)
float EffectOpacity = EffectAlpha;
// Figure out a universally visible highlight color.
FLinearColor HighlightTargetColorAndOpacity = ( (FLinearColor::White - ColorAndOpacity.Get())*0.5f + FLinearColor(+0.4f, +0.1f, -0.2f)) * InWidgetStyle.GetColorAndOpacityTint();
HighlightTargetColorAndOpacity.A = HighlightTargetOpacity * EffectOpacity * 255.0f;
// Compute the bounds offset of the highlight target from where the highlight target spring
// extents currently lie. This is used to "grow" or "shrink" the highlight as needed.
const float CommittingAnimOffset = CommittingAnimOffsetPercent * AllottedGeometry.Size.Y;
// Choose an offset amount depending on whether we're highlighting, or clearing highlight
const float EffectOffset = EffectAlpha * CommittingAnimOffset;
const float HighlightLeftX = HighlightTargetLeftSpring.GetPosition() - EffectOffset;
const float HighlightRightX = HighlightTargetRightSpring.GetPosition() + EffectOffset;
const float HighlightTopY = 0.0f - EffectOffset;
const float HighlightBottomY = AllottedGeometry.Size.Y + EffectOffset;
const FVector2D DrawPosition = FVector2D( HighlightLeftX, HighlightTopY );
const FVector2D DrawSize = FVector2D( HighlightRightX - HighlightLeftX, HighlightBottomY - HighlightTopY );
const FSlateBrush* StyleInfo = FEditorStyle::GetBrush("DetailsView.NameChangeCommitted");
// NOTE: We rely on scissor clipping for the highlight rectangle
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId + TextLayer,
AllottedGeometry.ToPaintGeometry( DrawPosition, DrawSize ), // Position, Size, Scale
StyleInfo, // Style
MyClippingRect, // Clipping rect
DrawEffects, // Effects to use
HighlightTargetColorAndOpacity ); // Color
}
return LayerId + TextLayer;
}
FText SObjectNameEditableTextBox::GetNameText() const
{
FString Result;
if (Objects.Num() == 1)
{
Result = GetObjectDisplayName(Objects[0]);
}
else if (Objects.Num() > 1)
{
if (!UserSetCommonName.IsEmpty())
{
Result = UserSetCommonName;
}
}
return FText::FromString(Result);
}
FText SObjectNameEditableTextBox::GetNameTooltipText() const
{
FText Result = FText::GetEmpty();
if (Objects.Num() == 0)
{
Result = LOCTEXT("EditableActorLabel_NoObjectsTooltip", "Nothing selected");
}
else if (Objects.Num() == 1 && Objects[0].IsValid())
{
if (CanEditNameText())
{
Result = FText::Format(LOCTEXT("EditableActorLabel_ActorTooltipFmt", "Rename the selected {0}"), FText::FromString(Objects[0].Get()->GetClass()->GetName()));
}
else if (Objects[0].Get()->IsA(AActor::StaticClass()))
{
Result = LOCTEXT("EditableActorLabel_NoEditActorTooltip", "Can't rename selected actor (its label isn't editable)");
}
else
{
Result = LOCTEXT("EditableActorLabel_NoEditObjectTooltip", "Can't rename selected object (only actors can have editable labels)");
}
}
else if (Objects.Num() > 1)
{
if (CanEditNameText())
{
Result = LOCTEXT("EditableActorLabel_MultiActorTooltip", "Rename multiple selected actors at once");
}
else
{
Result = LOCTEXT("EditableActorLabel_NoEditMultiObjectTooltip", "Can't rename selected objects (one or more aren't actors with editable labels)");
}
}
return Result;
}
EVisibility SObjectNameEditableTextBox::GetNameVisibility() const
{
if (Objects.Num() == 1 && Objects[0].IsValid())
{
if (CanEditNameText())
{
return EVisibility::Visible;
}
else if (Objects[0].Get()->IsA(AActor::StaticClass()))
{
return EVisibility::Visible;
}
else
{
return EVisibility::Collapsed;
}
}
else if (Objects.Num() > 1)
{
if (CanEditNameText())
{
return EVisibility::Visible;
}
else
{
return EVisibility::Collapsed;
}
}
return EVisibility::Collapsed;
}
FText SObjectNameEditableTextBox::GetNameHintText() const
{
FText Result;
if (Objects.Num() == 0)
{
Result = LOCTEXT("EditableActorLabel_NoObjectsHint", "<Nothing Selected>");
}
else if (Objects.Num() == 1 && Objects[0].IsValid())
{
Result = FText::Format(LOCTEXT("EditableActorLabel_MultiObjectsHint_SameType", "<Selected {0}>"), FText::FromName(Objects[0].Get()->GetClass()->GetFName()));
}
else if (Objects.Num() > 1)
{
Result = LOCTEXT("EditableActorLabel_MultiObjectsHint_DifferentTypes", "<Selected Objects>");
}
return Result;
}
void SObjectNameEditableTextBox::OnNameTextCommitted(const FText& NewText, ETextCommit::Type InTextCommit)
{
// Don't apply the change if the TextCommit type is OnCleared - this will only be the case if the keyboard focus was cleared due to
// Enter being pressed, in which case we will already have been here once with a TextCommit type of OnEnter.
if (InTextCommit != ETextCommit::OnCleared)
{
FText TrimmedText = FText::TrimPrecedingAndTrailing(NewText);
if (!TrimmedText.IsEmpty())
{
if (Objects.Num() == 1)
{
// Apply the change to the selected actor
AActor* Actor = Cast<AActor>(Objects[0].Get());
if(Actor != NULL)
{
const FScopedTransaction Transaction( LOCTEXT("RenameActorTransaction", "Rename Actor") );
if (Actor->IsActorLabelEditable())
{
Actor->SetActorLabel(TrimmedText.ToString());
LastCommittedTime = FSlateApplication::Get().GetCurrentTime();
RegisterActiveTimer( 0.f, FWidgetActiveTimerDelegate::CreateSP( this, &SObjectNameEditableTextBox::UpdateHighlightSpringState ) );
}
}
}
else if (Objects.Num() > 1)
{
const FScopedTransaction Transaction( LOCTEXT("RenameActorsTransaction", "Rename Multiple Actors") );
UserSetCommonName = TrimmedText.ToString();
for (int32 i=0; i<Objects.Num(); i++)
{
// Apply the change to the selected actor
if(Objects[i].IsValid() && Objects[i].Get()->IsA(AActor::StaticClass()))
{
AActor* Actor = (AActor*)Objects[i].Get();
if (Actor->IsActorLabelEditable())
{
Actor->SetActorLabel(TrimmedText.ToString());
LastCommittedTime = FSlateApplication::Get().GetCurrentTime();
RegisterActiveTimer( 0.f, FWidgetActiveTimerDelegate::CreateSP( this, &SObjectNameEditableTextBox::UpdateHighlightSpringState ) );
}
}
}
}
}
// Remove ourselves from the window focus so we don't get automatically reselected when scrolling around the context menu.
TSharedPtr< SWindow > ParentWindow = FSlateApplication::Get().FindWidgetWindow( SharedThis(this) );
if( ParentWindow.IsValid() )
{
ParentWindow->SetWidgetToFocusOnActivate( NULL );
}
}
// Clear Error
TextBox->SetError(FText::GetEmpty());
}
void SObjectNameEditableTextBox::OnTextChanged( const FText& InLabel )
{
FText TrimmedLabel = FText::TrimPrecedingAndTrailing(InLabel);
if (TrimmedLabel.IsEmpty())
{
TextBox->SetError(LOCTEXT( "RenameFailed_LeftBlank", "Names cannot be left blank" ));
}
else if (TrimmedLabel.ToString().Len() >= NAME_SIZE)
{
FFormatNamedArguments Arguments;
Arguments.Add( TEXT("CharCount"), NAME_SIZE );
TextBox->SetError(FText::Format(LOCTEXT("RenameFailed_TooLong", "Actor names must be less than {CharCount} characters long."), Arguments));
}
else
{
TextBox->SetError( FText::GetEmpty() );
}
}
bool SObjectNameEditableTextBox::CanEditNameText() const
{
bool Result = false;
if (Objects.Num() > 0)
{
Result = true;
for (int32 i=0; i<Objects.Num(); i++)
{
if(Objects[i].IsValid())
{
if (Objects[i].Get()->IsA(AActor::StaticClass()))
{
AActor* Actor = (AActor*)Objects[i].Get();
if (!Actor->IsActorLabelEditable())
{
// can't edit the name when a non-editable actor is selected
Result = false;
break;
}
}
else
{
// can't edit the name when a non-actor is selected
Result = false;
break;
}
}
}
}
return Result;
}
FString SObjectNameEditableTextBox::GetObjectDisplayName(TWeakObjectPtr<UObject> Object)
{
FString Result;
if(Object.IsValid())
{
UObject* ObjectPtr = Object.Get();
if (ObjectPtr->IsA(AActor::StaticClass()))
{
Result = ((AActor*)ObjectPtr)->GetActorLabel();
}
else
{
Result = ObjectPtr->GetName();
}
}
return Result;
}
// No code beyond this point
#undef LOCTEXT_NAMESPACE