Files
Unreal-CommonTime/Source/CommonTime/Private/DetailCustomizations/MyTimespanDetailCustomization.cpp

257 lines
6.9 KiB
C++
Raw Normal View History

2023-10-28 02:46:42 +02:00
// Copyright 2023 MrRobin. All Rights Reserved.
#include "DetailCustomizations/MyTimespanDetailCustomization.h"
#include "Containers/Array.h"
#include "Containers/UnrealString.h"
#include "DetailWidgetRow.h"
#include "Fonts/SlateFontInfo.h"
#include "HAL/PlatformCrt.h"
#include "Internationalization/Internationalization.h"
#include "Misc/Attribute.h"
#include "Misc/Timespan.h"
#include "PropertyHandle.h"
#include "Styling/AppStyle.h"
#include "Styling/ISlateStyle.h"
#include "UObject/NameTypes.h"
#include "UObject/UnrealType.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "DetailLayoutBuilder.h"
#include "Widgets/Input/SNumericEntryBox.h"
2023-10-28 20:43:30 +02:00
#include "Widgets/Input/SVectorInputBox.h"
#include "Widgets/Input/NumericTypeInterface.h"
#include "Widgets/Input/NumericUnitTypeInterface.inl"
#include "Math/UnitConversion.h"
2023-10-28 02:46:42 +02:00
#define LOCTEXT_NAMESPACE "MyTimespanDetailCustomization"
/* IDetailCustomization interface
*****************************************************************************/
void FMyTimespanDetailCustomization::CustomizeChildren(
TSharedRef<IPropertyHandle> StructPropertyHandle,
class IDetailChildrenBuilder& StructBuilder,
IPropertyTypeCustomizationUtils& StructCustomizationUtils)
{
/* do nothing */
}
void FMyTimespanDetailCustomization::CustomizeHeader(
TSharedRef<IPropertyHandle> StructPropertyHandle,
class FDetailWidgetRow& HeaderRow,
IPropertyTypeCustomizationUtils& StructCustomizationUtils)
{
PropertyHandle = StructPropertyHandle;
2023-10-28 23:18:17 +02:00
SAssignNew(HourEntryBox, SNumericEntryBox<double>)
2023-10-28 20:43:30 +02:00
.AllowSpin(true)
.MinValue(0)
.MaxValue(23)
.MinSliderValue(0)
.MaxSliderValue(23)
2023-10-28 23:18:17 +02:00
.MinFractionalDigits(0)
.MaxFractionalDigits(0)
2023-10-28 20:43:30 +02:00
.Font(IDetailLayoutBuilder::GetDetailFont())
.Value(this, &FMyTimespanDetailCustomization::OnGetValue, 0)
.OnValueChanged(this, &FMyTimespanDetailCustomization::OnValueChanged, 0)
.OnValueCommitted(this, &FMyTimespanDetailCustomization::OnValueCommitted, 0)
.OnBeginSliderMovement(this, &FMyTimespanDetailCustomization::OnBeginSliderMovement)
.OnEndSliderMovement(this, &FMyTimespanDetailCustomization::OnEndSliderMovement)
2023-10-28 23:18:17 +02:00
.TypeInterface(MakeShareable(new TNumericUnitTypeInterface<double>(EUnit::Hours)))
2023-10-28 20:43:30 +02:00
.LinearDeltaSensitivity(1);
2023-10-28 23:18:17 +02:00
SAssignNew(MinuteEntryBox, SNumericEntryBox<double>)
2023-10-28 20:43:30 +02:00
.AllowSpin(true)
.MinValue(0)
.MaxValue(59)
.MinSliderValue(0)
.MaxSliderValue(59)
2023-10-28 23:18:17 +02:00
.MinFractionalDigits(0)
.MaxFractionalDigits(0)
2023-10-28 20:43:30 +02:00
.Font(IDetailLayoutBuilder::GetDetailFont())
.Value(this, &FMyTimespanDetailCustomization::OnGetValue, 1)
.OnValueChanged(this, &FMyTimespanDetailCustomization::OnValueChanged, 1)
.OnValueCommitted(this, &FMyTimespanDetailCustomization::OnValueCommitted, 1)
.OnBeginSliderMovement(this, &FMyTimespanDetailCustomization::OnBeginSliderMovement)
.OnEndSliderMovement(this, &FMyTimespanDetailCustomization::OnEndSliderMovement)
2023-10-28 23:18:17 +02:00
.TypeInterface(MakeShareable(new TNumericUnitTypeInterface<double>(EUnit::Minutes)))
2023-10-28 20:43:30 +02:00
.LinearDeltaSensitivity(1);
2023-10-28 23:18:17 +02:00
SAssignNew(SecondEntryBox, SNumericEntryBox<double>)
2023-10-28 20:43:30 +02:00
.AllowSpin(true)
.MinValue(0)
.MaxValue(59)
.MinSliderValue(0)
.MaxSliderValue(59)
2023-10-28 23:18:17 +02:00
.MinFractionalDigits(0)
.MaxFractionalDigits(0)
2023-10-28 20:43:30 +02:00
.Font(IDetailLayoutBuilder::GetDetailFont())
.Value(this, &FMyTimespanDetailCustomization::OnGetValue, 2)
.OnValueChanged(this, &FMyTimespanDetailCustomization::OnValueChanged, 2)
.OnValueCommitted(this, &FMyTimespanDetailCustomization::OnValueCommitted, 2)
.OnBeginSliderMovement(this, &FMyTimespanDetailCustomization::OnBeginSliderMovement)
.OnEndSliderMovement(this, &FMyTimespanDetailCustomization::OnEndSliderMovement)
2023-10-28 23:18:17 +02:00
.TypeInterface(MakeShareable(new TNumericUnitTypeInterface<double>(EUnit::Seconds)))
2023-10-28 20:43:30 +02:00
.LinearDeltaSensitivity(1);
2023-10-28 02:46:42 +02:00
HeaderRow
.NameContent()
[
StructPropertyHandle->CreatePropertyNameWidget()
]
.ValueContent()
.MinDesiredWidth(125.0f * 3.0f)
2023-10-28 20:43:30 +02:00
.MaxDesiredWidth(125.0f * 3.0f)
2023-10-28 02:46:42 +02:00
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
2023-10-28 20:43:30 +02:00
.Padding(0.0f)
2023-10-28 02:46:42 +02:00
[
2023-10-28 20:43:30 +02:00
HourEntryBox.ToSharedRef()
2023-10-28 02:46:42 +02:00
]
+ SHorizontalBox::Slot()
2023-10-28 20:43:30 +02:00
.Padding(2.5f, 0.0f)
2023-10-28 02:46:42 +02:00
[
2023-10-28 20:43:30 +02:00
MinuteEntryBox.ToSharedRef()
2023-10-28 02:46:42 +02:00
]
+ SHorizontalBox::Slot()
2023-10-28 20:43:30 +02:00
.Padding(0.0f)
2023-10-28 02:46:42 +02:00
[
2023-10-28 20:43:30 +02:00
SecondEntryBox.ToSharedRef()
2023-10-28 02:46:42 +02:00
]
];
}
/* FMyTimespanDetailCustomization callbacks
*****************************************************************************/
2023-10-28 23:18:17 +02:00
TOptional<double> FMyTimespanDetailCustomization::OnGetValue(int32 Index) const
2023-10-28 02:46:42 +02:00
{
TArray<void*> RawData;
PropertyHandle->AccessRawData(RawData);
if (RawData.Num() != 1)
2023-10-28 23:18:17 +02:00
return TOptional<double>();
2023-10-28 02:46:42 +02:00
if (RawData[0] == nullptr)
2023-10-28 23:18:17 +02:00
return TOptional<double>();
2023-10-28 02:46:42 +02:00
auto* Timespan = ((FTimespan*)RawData[0]);
switch (Index)
{
case 0:
2023-10-28 23:18:17 +02:00
return TOptional<double>(Timespan->GetHours());
2023-10-28 02:46:42 +02:00
case 1:
2023-10-28 23:18:17 +02:00
return TOptional<double>(Timespan->GetMinutes());
2023-10-28 02:46:42 +02:00
case 2:
2023-10-28 23:18:17 +02:00
return TOptional<double>(Timespan->GetSeconds());
2023-10-28 02:46:42 +02:00
default:
2023-10-28 23:18:17 +02:00
return TOptional<double>();
2023-10-28 02:46:42 +02:00
}
}
void FMyTimespanDetailCustomization::OnBeginSliderMovement()
{
bIsUsingSlider = true;
GEditor->BeginTransaction(FText::Format(NSLOCTEXT("MyTimespanDetailCustomization", "SetTimespanProperty", "Edit {0}"), PropertyHandle->GetPropertyDisplayName()));
}
2023-10-28 23:18:17 +02:00
void FMyTimespanDetailCustomization::OnEndSliderMovement(double NewValue)
2023-10-28 02:46:42 +02:00
{
bIsUsingSlider = false;
GEditor->EndTransaction();
}
2023-10-28 23:18:17 +02:00
void FMyTimespanDetailCustomization::OnValueCommitted(double NewValue, ETextCommit::Type CommitType, int32 Index)
2023-10-28 02:46:42 +02:00
{
2023-10-28 23:18:17 +02:00
NewValue = FMath::CeilToDouble(NewValue);
2023-10-28 02:46:42 +02:00
TArray<void*> RawData;
PropertyHandle->AccessRawData(RawData);
PropertyHandle->NotifyPreChange();
for (auto RawDataInstance : RawData)
{
auto* Timespan = (FTimespan*)RawDataInstance;
int32 Hours = Timespan->GetHours();
int32 Minutes = Timespan->GetMinutes();
int32 Seconds = Timespan->GetSeconds();
switch (Index)
{
case 0:
*Timespan = FTimespan(NewValue, Minutes, Seconds);
break;
case 1:
*Timespan = FTimespan(Hours, NewValue, Seconds);
break;
case 2:
*Timespan = FTimespan(Hours, Minutes, NewValue);
break;
default:
break;
}
}
PropertyHandle->NotifyPostChange(EPropertyChangeType::ValueSet);
PropertyHandle->NotifyFinishedChangingProperties();
}
2023-10-28 23:18:17 +02:00
void FMyTimespanDetailCustomization::OnValueChanged(double NewValue, int32 Index)
2023-10-28 02:46:42 +02:00
{
if (!bIsUsingSlider)
return;
2023-10-28 23:18:17 +02:00
NewValue = FMath::CeilToDouble(NewValue);
2023-10-28 02:46:42 +02:00
TArray<void*> RawData;
PropertyHandle->AccessRawData(RawData);
PropertyHandle->NotifyPreChange();
for (auto RawDataInstance : RawData)
{
auto* Timespan = (FTimespan*)RawDataInstance;
int32 Hours = Timespan->GetHours();
int32 Minutes = Timespan->GetMinutes();
int32 Seconds = Timespan->GetSeconds();
switch (Index)
{
case 0:
*Timespan = FTimespan(NewValue, Minutes, Seconds);
break;
case 1:
*Timespan = FTimespan(Hours, NewValue, Seconds);
break;
case 2:
*Timespan = FTimespan(Hours, Minutes, NewValue);
break;
default:
break;
}
}
PropertyHandle->NotifyPostChange(EPropertyChangeType::ValueSet);
PropertyHandle->NotifyFinishedChangingProperties();
}
#undef LOCTEXT_NAMESPACE