Files
UnrealEngine/Engine/Source/Editor/DetailCustomizations/Private/TimecodeDetailsCustomization.cpp
2025-05-18 13:04:45 +08:00

123 lines
3.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "TimecodeDetailsCustomization.h"
#include "Containers/Array.h"
#include "Containers/UnrealString.h"
#include "CoreGlobals.h"
#include "DetailLayoutBuilder.h"
#include "DetailWidgetRow.h"
#include "Editor.h"
#include "Editor/EditorEngine.h"
#include "Fonts/SlateFontInfo.h"
#include "HAL/Platform.h"
#include "IDetailChildrenBuilder.h"
#include "Internationalization/Internationalization.h"
#include "Logging/LogCategory.h"
#include "Logging/LogMacros.h"
#include "Misc/Attribute.h"
#include "Misc/CString.h"
#include "Misc/Timecode.h"
#include "PropertyHandle.h"
#include "Trace/Detail/Channel.h"
#include "UObject/UnrealType.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/Input/SEditableTextBox.h"
#include "Widgets/Text/STextBlock.h"
#define LOCTEXT_NAMESPACE "Timecode"
void FTimecodeDetailsCustomization::CustomizeChildren(TSharedRef<IPropertyHandle> PropertyHandle, IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& CustomizationUtils)
{
TimecodeProperty = PropertyHandle;
ChildBuilder.AddProperty(PropertyHandle)
.CustomWidget()
.NameContent()
[
PropertyHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
SNew(SEditableTextBox)
.Text(this, &FTimecodeDetailsCustomization::OnGetTimecodeText)
.OnTextCommitted(this, &FTimecodeDetailsCustomization::OnTimecodeTextCommitted)
.SelectAllTextWhenFocused(true)
.RevertTextOnEscape(true)
.Font(IDetailLayoutBuilder::GetDetailFont())
.IsReadOnly_Lambda([this]()
{
return TimecodeProperty.IsValid() ? !TimecodeProperty->IsEditable() : false;
})
];
}
FText FTimecodeDetailsCustomization::OnGetTimecodeText() const
{
TArray<void*> RawData;
TimecodeProperty->AccessRawData(RawData);
if (RawData.Num())
{
FString CurrentValue = ((FTimecode*)RawData[0])->ToString();
return FText::FromString(CurrentValue);
}
return FText::GetEmpty();
}
void FTimecodeDetailsCustomization::OnTimecodeTextCommitted(const FText& InText, ETextCommit::Type CommitInfo)
{
TArray<void*> RawData;
TimecodeProperty->AccessRawData(RawData);
if (RawData.Num())
{
TArray<FString> Splits;
InText.ToString().ParseIntoArray(Splits, TEXT(":"));
const int NumSplits = Splits.Num();
if (NumSplits > 0 && NumSplits <= 4)
{
GEditor->BeginTransaction(FText::Format(LOCTEXT("SetTimecodeProperty", "Edit {0}"), TimecodeProperty->GetPropertyDisplayName()));
TimecodeProperty->NotifyPreChange();
((FTimecode*)RawData[0])->Hours = FCString::Atoi(*Splits[0]);
((FTimecode*)RawData[0])->Minutes = NumSplits > 1 ? FCString::Atoi(*Splits[1]) : 0;
if (NumSplits > 2)
{
TArray<FString> SubSplits;
Splits[2].ParseIntoArray(SubSplits, TEXT(";"));
const int NumSubSplits = SubSplits.Num();
((FTimecode*) RawData[0])->bDropFrameFormat = NumSubSplits != 1 ? true : false;
if (((FTimecode*) RawData[0])->bDropFrameFormat)
{
((FTimecode*) RawData[0])->Seconds = FCString::Atoi(*SubSplits[0]);
((FTimecode*) RawData[0])->Frames = NumSubSplits > 1 ? FCString::Atoi(*SubSplits[1]) : 0;
}
else
{
((FTimecode*) RawData[0])->Seconds = FCString::Atoi(*Splits[2]);
((FTimecode*) RawData[0])->Frames = NumSplits > 3 ? FCString::Atoi(*Splits[3]) : 0;
}
}
TimecodeProperty->NotifyPostChange(EPropertyChangeType::ValueSet);
TimecodeProperty->NotifyFinishedChangingProperties();
GEditor->EndTransaction();
}
else
{
UE_LOG(LogTemp, Error, TEXT("Unexpected timecode format. Expected 4 values, got %d"), Splits.Num());
}
}
}
#undef LOCTEXT_NAMESPACE