音量点

This commit is contained in:
Sch 2023-09-06 19:18:06 +08:00
parent 517f861869
commit 2b6dd72a30
13 changed files with 603 additions and 268 deletions

View File

@ -4,6 +4,7 @@
void FCursorCommands::RegisterCommands()
{
UI_COMMAND(OpenColorPanel, "打开颜色面板", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
UI_COMMAND(SetVolume, "设置音量", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
UI_COMMAND(Remove, "移除", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
}
#undef LOCTEXT_NAMESPACE

View File

@ -19,5 +19,6 @@ public:
TSharedPtr<FUICommandInfo> OpenColorPanel;
TSharedPtr<FUICommandInfo> Remove;
TSharedPtr<FUICommandInfo> SetVolume;
};

View File

@ -10,5 +10,6 @@ void FTimelineClipCommands::RegisterCommands()
UI_COMMAND(Cycle, "循环", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
UI_COMMAND(CancelCycle, "取消循环", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
UI_COMMAND(AddCursorHere, "在此处添加渐变点", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
UI_COMMAND(AddVolumeHere, "在此处添加音量点", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
}
#undef LOCTEXT_NAMESPACE

View File

@ -24,4 +24,5 @@ public:
TSharedPtr<FUICommandInfo> CancelCycle;
TSharedPtr<FUICommandInfo> Cycle;
TSharedPtr<FUICommandInfo> AddCursorHere;
TSharedPtr<FUICommandInfo> AddVolumeHere;
};

View File

@ -281,6 +281,12 @@ struct CUT5_API FPresetsCustomData
struct CUT5_API FVolumeData
{
FVolumeData () {};
FVolumeData(int32 Offset, int32 InVolume)
{
VolumeOffset = Offset;
Volume = InVolume;
};
int32 VolumeOffset = 0;
int32 Volume = 100;
@ -290,6 +296,11 @@ struct CUT5_API FVolumeData
Ar << VolumeData.Volume;
return Ar;
}
bool operator == (const FVolumeData& Other) const
{
return VolumeOffset == Other.VolumeOffset && Volume == Other.Volume;
}
};
struct CUT5_API FClipData : public TSharedFromThis<FClipData>
@ -602,6 +613,7 @@ public:
MoveTickCursor,
SelectClips,
ClipsMove,
VolumeDrag
};
FCutDragDropBase() {};
FCutDragDropBase(EType InType)
@ -695,6 +707,7 @@ class CUT5_API FCursorDragDrop final : public FCutDragDropBase
{
public:
FCursorData* CursorData;
FVolumeData* VolumeData;
FClipData* ClipData;
};

View File

@ -423,6 +423,18 @@ void DragDropOperator::OnDragOver(const FGeometry& MyGeometry, const FDragDropEv
float Offset = LocalPos.X;
DragDrop->CursorData->CursorFrameOffset = Offset / FGlobalData::DefaultTimeTickSpace - DragDrop->ClipData->ClipStartFrame;
}
if (DragDrop->DragDropType == FCutDragDropBase::EType::VolumeDrag)
{
TSharedPtr<STrackBody> Body = StaticCastSharedPtr<STrackBody>(DragDrop->OverrideWidget);
const FVector2D LocalPos = Body->GetCachedGeometry().AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition());
if (LocalPos.X <= DragDrop->ClipData->ClipStartFrame * FGlobalData::DefaultTimeTickSpace || LocalPos.X >= DragDrop->ClipData->ClipEndFrame * FGlobalData::DefaultTimeTickSpace)
{
return;
}
float Offset = LocalPos.X;
DragDrop->VolumeData->VolumeOffset = Offset / FGlobalData::DefaultTimeTickSpace - DragDrop->ClipData->ClipStartFrame;
}
}
const auto& DragDropOperation = static_cast<FClip2ClipDragDropOperation&>(DragDropEvent.GetOperation().ToSharedRef().Get());

View File

@ -0,0 +1,162 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "SClipVolumeCursor.h"
#include "SlateOptMacros.h"
// #include "AppFramework/Public/Widgets/Colors/SColorPicker.h"
#include "Cut5/Utils/Utils.h"
#include "Cut5/Widgets/STimelineClip.h"
#include "Cut5/Widgets/Commands/CursorCommands.h"
#include "Widgets/Input/SSpinBox.h"
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SClipVolumeCursor::Construct(const FArguments& InArgs)
{
CursorData = InArgs._CursorData;
ClipData = InArgs._ClipData;
TimelineClip = InArgs._TimelineClip;
ChildSlot
[
SNew(SBox)
.WidthOverride(23)
.HeightOverride(23)
[
SNew(SImage)
.Image(FUtils::GetBrushFromImage(FUtils::GetResourcesPath(TEXT("Cursor.png")), {}))
.OnMouseButtonDown_Lambda([this](const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
{
const TSharedPtr<FCursorDragDrop> Operation = MakeShared<FCursorDragDrop>();
Operation->DragDropType = FCutDragDropBase::EType::VolumeDrag;
Operation->VolumeData = CursorData;
Operation->ClipData = ClipData;
Operation->OverrideWidget = TimelineClip->Body;
// TimelineClip->MainWidgetInterface->UpdateProperties(this);
return FReply::Handled().DetectDrag(SharedThis(this), EKeys::LeftMouseButton).BeginDragDrop(Operation.ToSharedRef());
}
else if (MouseEvent.IsMouseButtonDown(EKeys::RightMouseButton))
{
FMenuBuilder MenuBuilder(true, CommandList);
// MenuBuilder.AddMenuEntry(FCursorCommands::Get().OpenColorPanel);
MenuBuilder.AddMenuEntry(FCursorCommands::Get().Remove);
MenuBuilder.AddWidget(SNew(SSpinBox<int32>)
.MaxValue(100)
.MinValue(0)
.Value(CursorData->Volume)
.OnValueChanged_Lambda([this](const int32& Value)
{
CursorData->Volume = Value;
}), FText::FromString(TEXT("音量")), true);
FSlateApplication::Get().PushMenu(AsShared(), FWidgetPath(), MenuBuilder.MakeWidget(), FSlateApplication::Get().GetCursorPos(), FPopupTransitionEffect::ContextMenu);
}
return FReply::Handled();
})
]
];
SetRenderTransform(FSlateRenderTransform(FVector2D(CursorData->VolumeOffset * FGlobalData::DefaultTimeTickSpace - 11, 0)));
FCursorCommands::Register();
CommandList = MakeShared<FUICommandList>();
CommandList->MapAction(FCursorCommands::Get().SetVolume, FExecuteAction::CreateLambda([this]()
{
for (int32 i = 0; i < ClipData->VolumeData.Num(); i++)
{
if (ClipData->VolumeData[i] == *CursorData)
{
}
}
}));
CommandList->MapAction(FCursorCommands::Get().Remove, FExecuteAction::CreateLambda([this]()
{
for (int32 i = 0; i < ClipData->VolumeData.Num(); i++)
{
if (ClipData->VolumeData[i] == *CursorData)
{
ClipData->VolumeData.RemoveAt(i);
break;
}
}
}));
}
void SClipVolumeCursor::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
{
SetRenderTransform(FSlateRenderTransform(FVector2D(CursorData->VolumeOffset * FGlobalData::DefaultTimeTickSpace - 11, 0)));
}
FReply SClipVolumeCursor::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
{
}
return FReply::Handled();
}
TSharedPtr<SWidget> SClipVolumeCursor::GetPropertiesWidget()
{
TSharedPtr<SVerticalBox> VerticalBox = SNew(SVerticalBox);
FTextBlockStyle NormalText = FAppStyle::GetWidgetStyle<FTextBlockStyle>("NormalText");
NormalText.SetFontSize(13);
VerticalBox->AddSlot()
.Padding(0, 13, 0, 0)
[
SNew(SBox).HeightOverride(32).WidthOverride(214)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
.VAlign(VAlign_Center)
[
SNew(SBox)
.WidthOverride(62)
.HeightOverride(32)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("音量")))
.Font(NormalText.Font)
.Justification(ETextJustify::Center)
]
]
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
[
SNew(SBox)
.WidthOverride(136)
.HeightOverride(32)
[
SNew(SSpinBox<int32>)
.Value_Lambda([this]()
{
if (!CursorData)
return 0;
return CursorData->Volume;
})
.MinValue(0)
.MaxValue(100)
.OnValueChanged_Lambda([this](const int32& Value)
{
if (!CursorData)
return;
CursorData->Volume = Value;
})
]
]
]
];
return VerticalBox;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

View File

@ -0,0 +1,34 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Cut5/Interface/PropertiesInterface.h"
#include "Cut5/Widgets/DefineGlobal.h"
#include "Widgets/SCompoundWidget.h"
/**
*
*/
class CUT5_API SClipVolumeCursor : public SCompoundWidget, public IPropertiesInterface
{
public:
SLATE_BEGIN_ARGS(SClipVolumeCursor)
{
}
SLATE_ARGUMENT(FVolumeData*, CursorData);
SLATE_ARGUMENT(FClipData*, ClipData);
SLATE_ARGUMENT(class STimelineClip*, TimelineClip);
SLATE_END_ARGS()
/** Constructs this widget with InArgs */
void Construct(const FArguments& InArgs);
virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override;
FVolumeData* CursorData = nullptr;
FClipData* ClipData = nullptr;
class STimelineClip* TimelineClip = nullptr;
virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
TSharedPtr<FUICommandList> CommandList;
virtual TSharedPtr<SWidget> GetPropertiesWidget() override;
};

View File

@ -44,8 +44,6 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
SAssignNew(StatePanel, SStatePanel);
SAssignNew(CustomPanel, SCustomPanel);
FTextBlockStyle MainBarTextStyle = FAppStyle::GetWidgetStyle<FTextBlockStyle>("NormalText");
MainBarTextStyle.SetFontSize(14);
FTextBlockStyle TitleBarTextStyle = FAppStyle::GetWidgetStyle<FTextBlockStyle>("NormalText");
@ -1772,26 +1770,44 @@ tinyxml2::XMLElement* SCutMainWindow::GetVideoElement(tinyxml2::XMLElement* Pare
Mode->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(0)));
}
tinyxml2::XMLElement* VolumeEventList = Video->InsertNewChildElement("VolumeEventList");
{
tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent");
if (EncodeVideoInfo.TrackData.IsMute)
{
tinyxml2::XMLElement* VolumeEventTimeCode = VolumeEvent->InsertNewChildElement("TimeCode");
tinyxml2::XMLElement* VolumeEventValue = VolumeEvent->InsertNewChildElement("Value");
if (EncodeVideoInfo.TrackData.IsMute)
tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent");
VolumeEvent->InsertNewChildElement("TimeCode")->InsertNewText("0");
VolumeEvent->InsertNewChildElement("Value")->InsertNewText("0");
}
else
{
if (EncodeVideoInfo.ClipData.VolumeData.Num() > 0)
{
VolumeEventTimeCode->InsertNewText("0");
VolumeEventValue->InsertNewText("0");
tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent");
VolumeEvent->InsertNewChildElement("TimeCode")->InsertNewText("0");
VolumeEvent->InsertNewChildElement("Value")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(EncodeVideoInfo.ClipData.VolumeData[0].Volume)));
}
else
{
// TODO: Dynamic Volume
VolumeEventTimeCode->InsertNewText("0");
VolumeEventValue->InsertNewText("100");
tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent");
VolumeEvent->InsertNewChildElement("TimeCode")->InsertNewText("0");
VolumeEvent->InsertNewChildElement("Value")->InsertNewText("0");
}
}
for (const FVolumeData& Volume : EncodeVideoInfo.ClipData.VolumeData)
{
tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent");
{
tinyxml2::XMLElement* VolumeEventTimeCode = VolumeEvent->InsertNewChildElement("TimeCode");
tinyxml2::XMLElement* VolumeEventValue = VolumeEvent->InsertNewChildElement("Value");
VolumeEventTimeCode->InsertNewText(TCHAR_TO_UTF8(*FUtils::GetMsFromString(FGlobalData::GetTimeData(Volume.VolumeOffset))));
VolumeEventValue->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(Volume.Volume)));
}
}
}
tinyxml2::XMLElement* ProjectorID = Video->InsertNewChildElement("ProjectorID");
{
@ -1891,21 +1907,37 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundElement(tinyxml2::XMLElement* Pare
tinyxml2::XMLElement* VolumeEventList = Sound->InsertNewChildElement("VolumeEventList");
{
tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent");
if (EncodeVideoInfo.TrackData.IsMute)
{
tinyxml2::XMLElement* VolumeEventTimeCode = VolumeEvent->InsertNewChildElement("TimeCode");
tinyxml2::XMLElement* VolumeEventValue = VolumeEvent->InsertNewChildElement("Value");
if (EncodeVideoInfo.TrackData.IsMute)
tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent");
VolumeEvent->InsertNewChildElement("TimeCode")->InsertNewText("0");
VolumeEvent->InsertNewChildElement("Value")->InsertNewText("0");
}
else
{
if (EncodeVideoInfo.ClipData.VolumeData.Num() > 0)
{
VolumeEventTimeCode->InsertNewText("0");
VolumeEventValue->InsertNewText("0");
tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent");
VolumeEvent->InsertNewChildElement("TimeCode")->InsertNewText("0");
VolumeEvent->InsertNewChildElement("Value")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(EncodeVideoInfo.ClipData.VolumeData[0].Volume)));
}
else
{
// TODO: Dynamic Volume
VolumeEventTimeCode->InsertNewText("0");
VolumeEventValue->InsertNewText("100");
tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent");
VolumeEvent->InsertNewChildElement("TimeCode")->InsertNewText("0");
VolumeEvent->InsertNewChildElement("Value")->InsertNewText("0");
}
}
for (const FVolumeData& Volume : EncodeVideoInfo.ClipData.VolumeData)
{
tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent");
{
tinyxml2::XMLElement* VolumeEventTimeCode = VolumeEvent->InsertNewChildElement("TimeCode");
tinyxml2::XMLElement* VolumeEventValue = VolumeEvent->InsertNewChildElement("Value");
VolumeEventTimeCode->InsertNewText(TCHAR_TO_UTF8(*FUtils::GetMsFromString(FGlobalData::GetTimeData(Volume.VolumeOffset))));
VolumeEventValue->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(Volume.Volume)));
}
}
}

View File

@ -24,6 +24,7 @@
#include "HAL/ThreadManager.h"
#include "MicroWidgets/SNewProjectTips.h"
#include "Presets/SClipCursor.h"
#include "Presets/SClipVolumeCursor.h"
#include "Rendering/DrawElementPayloads.h"
#include "Slate/Private/Framework/Application/Menu.h"
#include "TimelineClips/ClipProxy.h"
@ -56,6 +57,11 @@ FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const F
MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().Fill2Start);
MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().Fill2End);
}
if (ClipData->ClipType == ETrackType::VideoTrack || ClipData->ClipType == ETrackType::AudioTrack || ClipData->ClipType == ETrackType::AudioTrackR)
{
MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().AddVolumeHere);
}
if (ClipData->ClipType != ETrackType::ProjectorTrack)
{
if (ClipData->bIsCycle)
@ -268,6 +274,28 @@ void STimelineClip::Construct(const FArguments& InArgs)
NewClipCursor.ToSharedRef()
];
}
}
if (ClipData->ClipType == ETrackType::VideoTrack ||
ClipData->ClipType == ETrackType::AudioTrack ||
ClipData->ClipType == ETrackType::AudioTrackR)
{
for (int32 i = 0; i < ClipData->VolumeData.Num(); i++)
{
TSharedPtr<SClipVolumeCursor> NewClipCursor =
SNew(SClipVolumeCursor)
.CursorData(&ClipData->VolumeData[i])
.ClipData(ClipData)
.TimelineClip(this);
ClipOverlay->AddSlot()
.HAlign(HAlign_Left)
.VAlign(VAlign_Center)
[
NewClipCursor.ToSharedRef()
];
}
}
@ -546,6 +574,14 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe
bool bParentEnabled) const
{
if (ClipData->ClipType == ETrackType::AudioTrack || ClipData->ClipType == ETrackType::AudioTrackR)
{
const FSlateBrush Brush;
FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 5, AllottedGeometry.ToPaintGeometry(),
&Brush, ESlateDrawEffect::None, FLinearColor(1.0, 0.0, 1.0, 1.0));
}
const float XLength = AllottedGeometry.GetLocalSize().X;
const float TotalLength = ((ClipData->ClipEndFrame - ClipData->ClipStartFrame) * FGlobalData::DefaultTimeTickSpace);
{

View File

@ -49,7 +49,10 @@ void STrackBody::Construct(const FArguments& InArgs)
{
AddCursor(SelectedClipGUID);
}), FCanExecuteAction());
CommandList->MapAction(FTimelineClipCommands::Get().AddVolumeHere, FExecuteAction::CreateLambda([this]()
{
AddVolume(SelectedClipGUID);
}), FCanExecuteAction());
MainWidgetInterface = InArgs._MainWidgetInterface;
TrackHead = InArgs._TrackHead;
ChildSlot
@ -225,6 +228,27 @@ void STrackBody::AddCursor(const FGuid& Guid)
}
}
void STrackBody::AddVolume(const FGuid& Guid)
{
for (int32 i = 0; i < SlateClips.Num(); i++)
{
if (TrackHead->TrackData.ClipData[i].ClipGuid == Guid)
{
TrackHead->TrackData.ClipData[i].VolumeData.Add(
FVolumeData(SelectedClipFrame, 50));
Sort(TrackHead->TrackData.ClipData[i].VolumeData.GetData(),
TrackHead->TrackData.ClipData[i].VolumeData.Num(),
[](const FVolumeData& VolumeA, const FVolumeData& VolumeB)
{
return VolumeA.VolumeOffset < VolumeB.VolumeOffset;
});
CallRender();
break;
}
}
}
void STrackBody::Fill2End(const FGuid& Guid)
{
for (int32 i = 0; i < SlateClips.Num(); i++)

View File

@ -38,6 +38,7 @@ public:
void Fill2End(const FGuid& Guid);
void SetCycle(const FGuid& Guid, bool Cycle);
void AddCursor(const FGuid& Guid);
void AddVolume(const FGuid& Guid);
// virtual bool CanDragOver() override;

View File

@ -51,271 +51,288 @@ TSharedPtr<SWidget> FClipProxy::GetPropertiesWidget()
FTextBlockStyle NormalText = FAppStyle::GetWidgetStyle<FTextBlockStyle>("NormalText");
NormalText.SetFontSize(13);
return PropertiesWidget =
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.Padding(0, 13, 0, 0)
[
SNew(SBox).HeightOverride(32).WidthOverride(214)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
.VAlign(VAlign_Center)
[
SNew(SBox)
.WidthOverride(62)
.HeightOverride(32)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("颜色")))
.Font(NormalText.Font)
.Justification(ETextJustify::Center)
]
]
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
[
SNew(SBox)
.WidthOverride(136)
.HeightOverride(32)
[
SNew(SImage)
.Image(FUtils::GetBrushFromImage(FUtils::GetResourcesPath("Color.png"), {}))
.ColorAndOpacity_Raw(this, &FClipProxy::GetColor)
.OnMouseButtonDown_Lambda([this](const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
MainInterface->OpenColorPanel(&ClipData->PresetsCustomData.Colors[0]);
return FReply::Handled();
})
]
]
]
]
+ SVerticalBox::Slot()
.Padding(0, 13, 0, 0)
[
SNew(SBox).HeightOverride(32).WidthOverride(214)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
.VAlign(VAlign_Center)
[
SNew(SBox)
.WidthOverride(62)
.HeightOverride(32)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("动效")))
.Font(NormalText.Font)
.Justification(ETextJustify::Center)
]
]
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
[
SNew(SBox)
.WidthOverride(136)
.HeightOverride(32)
[
SNew(SComboBox<TSharedPtr<FString>>)
.OptionsSource(&Selectable)
.OnGenerateWidget_Lambda([this](TSharedPtr<FString> InItem)
{
return SNew(STextBlock).Text(FText::FromString(*InItem));
})
.OnSelectionChanged_Lambda([this](TSharedPtr<FString> InItem, ESelectInfo::Type SelectInfo)
{
switch (Selectable.Find(InItem))
{
case 0:
ClipData->PresetsCustomData.PresetCustomType = FPresetsCustomData::EPresetCustomType::None;
break;
case 1:
ClipData->PresetsCustomData.PresetCustomType = FPresetsCustomData::EPresetCustomType::Breathe;
break;
case 2:
ClipData->PresetsCustomData.PresetCustomType = FPresetsCustomData::EPresetCustomType::Flash;
break;
case 3:
{
ClipData->PresetsCustomData.PresetCustomType = FPresetsCustomData::EPresetCustomType::Gradient;
if (ClipData->PresetsCustomData.Cursors.Num() < 2)
{
ClipData->PresetsCustomData.Cursors.Empty();
ClipData->PresetsCustomData.Cursors.Add(FCursorData(0, FLinearColor::Red));
ClipData->PresetsCustomData.Cursors.Add(FCursorData(10, FLinearColor::Green));
}
}
default:
break;
}
MainInterface->GetCutTimeline()->RenderGroup();
})
TSharedPtr<SVerticalBox> VerticalBox;
PropertiesWidget = SAssignNew(VerticalBox, SVerticalBox);
if (ClipData->PresetType != EPresetType::NotAPresets)
{ // 颜色
VerticalBox->AddSlot()
.Padding(0, 13, 0, 0)
[
SNew(SBox).HeightOverride(32).WidthOverride(214)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
.VAlign(VAlign_Center)
[
SNew(SBox)
.WidthOverride(62)
.HeightOverride(32)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text_Lambda([this]()
.Text(FText::FromString(TEXT("颜色")))
.Font(NormalText.Font)
.Justification(ETextJustify::Center)
]
]
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
[
SNew(SBox)
.WidthOverride(136)
.HeightOverride(32)
[
SNew(SImage)
.Image(FUtils::GetBrushFromImage(FUtils::GetResourcesPath("Color.png"), {}))
.ColorAndOpacity_Raw(this, &FClipProxy::GetColor)
.OnMouseButtonDown_Lambda([this](const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (!ClipData)
return FText();
return FText::FromString( ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::None ? TEXT("") : ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Breathe ? TEXT("呼吸") : ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Gradient ? TEXT("渐变") : TEXT("闪烁"));
MainInterface->OpenColorPanel(&ClipData->PresetsCustomData.Colors[0]);
return FReply::Handled();
})
]
]
]
]
]
+ SVerticalBox::Slot()
.Padding(0, 13, 0, 0)
[
SNew(SBox).HeightOverride(32).WidthOverride(214)
];
// 动效
VerticalBox->AddSlot()
.Padding(0, 13, 0, 0)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
.VAlign(VAlign_Center)
SNew(SBox).HeightOverride(32).WidthOverride(214)
[
SNew(SBox)
.WidthOverride(62)
.HeightOverride(32)
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("次数")))
.Font(NormalText.Font)
.Justification(ETextJustify::Center)
SNew(SBox)
.WidthOverride(62)
.HeightOverride(32)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("动效")))
.Font(NormalText.Font)
.Justification(ETextJustify::Center)
]
]
]
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
[
SNew(SBox)
.WidthOverride(136)
.HeightOverride(32)
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
[
SNew(SSpinBox<int32>)
.Value_Lambda([this]()
{
if (!ClipData)
return 0;
return ClipData->PresetsCustomData.Times;
})
.MinValue(1)
.MaxValue(200)
.OnValueChanged_Lambda([this](const int32& Value)
{
if (!ClipData)
return;
ClipData->PresetsCustomData.Times = Value;
})
]
]
]
]
+ SVerticalBox::Slot()
.Padding(0, 13, 0, 0)
[
SNew(SBox).HeightOverride(32).WidthOverride(214)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
.VAlign(VAlign_Center)
[
SNew(SBox)
.WidthOverride(62)
.HeightOverride(32)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("时间")))
.Font(NormalText.Font)
.Justification(ETextJustify::Center)
]
]
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
[
SNew(SBox)
.WidthOverride(136)
.HeightOverride(32)
[
SNew(SSpinBox<float>)
.Value(0.3)
.MinValue(0.3)
.OnValueChanged_Lambda([this](const float& Value)
{
if (!ClipData)
return;
ClipData->ClipEndFrame = ClipData->ClipStartFrame + Value * FGlobalData::GlobalFPS;
ClipData->PresetsCustomData.Time = (ClipData->ClipEndFrame - ClipData->ClipStartFrame) / FGlobalData::GlobalFPS;
MainInterface->GetCutTimeline()->RenderGroup();
})
.Value_Lambda([this]()
{
if (!ClipData)
return 0.0f;
return (ClipData->ClipEndFrame - ClipData->ClipStartFrame) / FGlobalData::GlobalFPS;
})
// .TypeInterface(MakeShared<TNumericUnitTypeInterface<int32>>(EUnit::Seconds))
]
]
]
]
+ SVerticalBox::Slot()
.SizeParam(FStretch(1.0))
[
SNew(SSpacer)
]
+ SVerticalBox::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Bottom)
.Padding(0, 0, 0, 24)
[
SNew(SBox).HeightOverride(40).WidthOverride(144)
[
SNew(SOverlay)
+ SOverlay::Slot()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(SImage)
.Image(FUtils::GetBrushFromImage(FUtils::GetResourcesPath("SaveCustomPreset.png"), {144, 40}))
.OnMouseButtonDown_Lambda([this](const FGeometry&, const FPointerEvent&)
{
TSharedPtr<SNewProjectTips> NewProjectTips = SNew(SNewProjectTips).Title(TEXT("保存自定义效果名称"));
NewProjectTips->OnEnsure.BindLambda([this, NewProjectTips](const FString& String)
SNew(SBox)
.WidthOverride(136)
.HeightOverride(32)
[
SNew(SComboBox<TSharedPtr<FString>>)
.OptionsSource(&Selectable)
.OnGenerateWidget_Lambda([this](TSharedPtr<FString> InItem)
{
TimelineClip->MainWidgetInterface->AddNewCustomPreset(String, ClipData->PresetsCustomData);
GEngine->GameViewport->RemoveViewportWidgetContent(NewProjectTips.ToSharedRef());
});
GEngine->GameViewport->AddViewportWidgetContent(NewProjectTips.ToSharedRef()
, 1);
return FReply::Handled();
})
return SNew(STextBlock).Text(FText::FromString(*InItem));
})
.OnSelectionChanged_Lambda([this](TSharedPtr<FString> InItem, ESelectInfo::Type SelectInfo)
{
switch (Selectable.Find(InItem))
{
case 0:
ClipData->PresetsCustomData.PresetCustomType = FPresetsCustomData::EPresetCustomType::None;
break;
case 1:
ClipData->PresetsCustomData.PresetCustomType = FPresetsCustomData::EPresetCustomType::Breathe;
break;
case 2:
ClipData->PresetsCustomData.PresetCustomType = FPresetsCustomData::EPresetCustomType::Flash;
break;
case 3:
{
ClipData->PresetsCustomData.PresetCustomType = FPresetsCustomData::EPresetCustomType::Gradient;
if (ClipData->PresetsCustomData.Cursors.Num() < 2)
{
ClipData->PresetsCustomData.Cursors.Empty();
ClipData->PresetsCustomData.Cursors.Add(FCursorData(0, FLinearColor::Red));
ClipData->PresetsCustomData.Cursors.Add(FCursorData(10, FLinearColor::Green));
}
}
default:
break;
}
MainInterface->GetCutTimeline()->RenderGroup();
})
[
SNew(STextBlock)
.Text_Lambda([this]()
{
if (!ClipData)
return FText();
return FText::FromString( ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::None ? TEXT("") : ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Breathe ? TEXT("呼吸") : ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Gradient ? TEXT("渐变") : TEXT("闪烁"));
})
]
]
]
]
+ SOverlay::Slot()
];
// 次数
VerticalBox->AddSlot()
.Padding(0, 13, 0, 0)
[
SNew(SBox).HeightOverride(32).WidthOverride(214)
[
SNew(STextBlock)
.Visibility(EVisibility::HitTestInvisible)
.Text(FText::FromString((TEXT("保存自定义效果"))))
.Font(NormalText.Font)
.Justification(ETextJustify::Center)
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
.VAlign(VAlign_Center)
[
SNew(SBox)
.WidthOverride(62)
.HeightOverride(32)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("次数")))
.Font(NormalText.Font)
.Justification(ETextJustify::Center)
]
]
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
[
SNew(SBox)
.WidthOverride(136)
.HeightOverride(32)
[
SNew(SSpinBox<int32>)
.Value_Lambda([this]()
{
if (!ClipData)
return 0;
return ClipData->PresetsCustomData.Times;
})
.MinValue(1)
.MaxValue(200)
.OnValueChanged_Lambda([this](const int32& Value)
{
if (!ClipData)
return;
ClipData->PresetsCustomData.Times = Value;
})
]
]
]
]
];
// TODO: 配置文件保存自定义效果
// TODO: 自定义效果拖拽到轨道
];
// 时间
VerticalBox->AddSlot()
.Padding(0, 13, 0, 0)
[
SNew(SBox).HeightOverride(32).WidthOverride(214)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
.VAlign(VAlign_Center)
[
SNew(SBox)
.WidthOverride(62)
.HeightOverride(32)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("时间")))
.Font(NormalText.Font)
.Justification(ETextJustify::Center)
]
]
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
[
SNew(SBox)
.WidthOverride(136)
.HeightOverride(32)
[
SNew(SSpinBox<float>)
.Value(0.3)
.MinValue(0.3)
.OnValueChanged_Lambda([this](const float& Value)
{
if (!ClipData)
return;
ClipData->ClipEndFrame = ClipData->ClipStartFrame + Value * FGlobalData::GlobalFPS;
ClipData->PresetsCustomData.Time = (ClipData->ClipEndFrame - ClipData->ClipStartFrame) / FGlobalData::GlobalFPS;
MainInterface->GetCutTimeline()->RenderGroup();
})
.Value_Lambda([this]()
{
if (!ClipData)
return 0.0f;
return (ClipData->ClipEndFrame - ClipData->ClipStartFrame) / FGlobalData::GlobalFPS;
})
// .TypeInterface(MakeShared<TNumericUnitTypeInterface<int32>>(EUnit::Seconds))
]
]
]
];
// 保存自定义效果
VerticalBox->AddSlot()
.SizeParam(FStretch(1.0))
[
SNew(SSpacer)
];
VerticalBox->AddSlot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Bottom)
.Padding(0, 0, 0, 24)
[
SNew(SBox).HeightOverride(40).WidthOverride(144)
[
SNew(SOverlay)
+ SOverlay::Slot()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(SImage)
.Image(FUtils::GetBrushFromImage(FUtils::GetResourcesPath("SaveCustomPreset.png"), {144, 40}))
.OnMouseButtonDown_Lambda([this](const FGeometry&, const FPointerEvent&)
{
TSharedPtr<SNewProjectTips> NewProjectTips = SNew(SNewProjectTips).Title(TEXT("保存自定义效果名称"));
NewProjectTips->OnEnsure.BindLambda([this, NewProjectTips](const FString& String)
{
TimelineClip->MainWidgetInterface->AddNewCustomPreset(String, ClipData->PresetsCustomData);
GEngine->GameViewport->RemoveViewportWidgetContent(NewProjectTips.ToSharedRef());
});
GEngine->GameViewport->AddViewportWidgetContent(NewProjectTips.ToSharedRef()
, 1);
return FReply::Handled();
})
]
+ SOverlay::Slot()
[
SNew(STextBlock)
.Visibility(EVisibility::HitTestInvisible)
.Text(FText::FromString((TEXT("保存自定义效果"))))
.Font(NormalText.Font)
.Justification(ETextJustify::Center)
]
]
];
}
return PropertiesWidget;
}
void FClipProxy::Reset()