1. 微调 O
3. ctrls手动保存 O
4. 独立特效卡永久保存,拖拽进组和特效卡会复制特效卡,复制卡片与原本卡片共享,只有删除原本卡片复制卡片才会消失 O
5. 组合卡片没有轨道 O
6. 拖拽全选坐标计算
7. 拖拽动画
8. 拉条更新指针动画 O
9. wav无法读取
10. 右键资产删除 O
11. 单选择改为被迫全选 O
12. 固定帧数
13. 预设片段实例保存
14. 剪刀显示时间码 O
15. 删除自定义预设会导致崩溃
This commit is contained in:
Sch 2023-08-24 18:58:49 +08:00
parent fa8ecab21f
commit de15282a40
18 changed files with 781 additions and 104 deletions

View File

@ -166,9 +166,9 @@ TArray<FEncodeVideoInfo> FUtils::TrackEncodeVideo(const FTrackData& TrackData, c
FString StartTime = FString::Printf(TEXT("%02d:%02d:%02d"), StartTimespan.GetHours(), StartTimespan.GetMinutes(), StartTimespan.GetSeconds());
FString EndTime = FString::Printf(TEXT("%02d:%02d:%02d"), EndTimespan.GetHours(), EndTimespan.GetMinutes(), EndTimespan.GetSeconds());
FString InputFile = TempClipData.ResourcePropertyDataPtr->MoviePath;
FString InputFile = "\"" + TempClipData.ResourcePropertyDataPtr->MoviePath + "\"";
FString OutputFile = FPaths::ConvertRelativePathToFull(ExportPath + FString::FromInt(i) + TEXT(".mp4"));
FString OutputFile = "\"" + FPaths::ConvertRelativePathToFull(ExportPath + FString::FromInt(i) + TEXT(".mp4")) + "\"";
int32 StartFrame = (TempClipData.VideoStartFrame) % static_cast<int>(FGlobalData::GlobalFPS);;
int32 EndFrame = (TempClipData.VideoEndFrame) % static_cast<int>(FGlobalData::GlobalFPS);
@ -183,6 +183,10 @@ TArray<FEncodeVideoInfo> FUtils::TrackEncodeVideo(const FTrackData& TrackData, c
EncodeVideoInfo.EncodedVideoName = ExportPath + FString::FromInt(i) + TEXT(".mp4");
EncodeVideoInfo.ClipStartFrame = TempClipData.ClipStartFrame;
EncodeVideoInfo.ClipEndFrame = TempClipData.ClipEndFrame;
EncodeVideoInfo.TrackData = TrackData;
EncodeVideoInfo.ClipData = TempClipData;
EncodeVideoInfos.Add(EncodeVideoInfo);
}
i++;
@ -241,6 +245,9 @@ TArray<FEncodeVideoInfo> FUtils::TrackEncodeAudio(const FTrackData& TrackData, c
EncodeVideoInfo.EncodedVideoName = ExportPath + FString::FromInt(i) + TEXT(".mp3");
EncodeVideoInfo.ClipStartFrame = TempClipData.ClipStartFrame;
EncodeVideoInfo.ClipEndFrame = TempClipData.ClipEndFrame;
EncodeVideoInfo.TrackData = TrackData;
EncodeVideoInfo.ClipData = TempClipData;
EncodeVideoInfos.Add(EncodeVideoInfo);
}
i++;
@ -496,6 +503,9 @@ TArray<FEncodeVideoInfo> FUtils::ExportPsaf(FTrackData TrackData, const FString&
FEncodeVideoInfo EncodeVideoInfo;
EncodeVideoInfo.EncodedVideoName = ExportName + FString::FromInt(i) + ".psaf";
EncodeVideoInfo.EncodedVideoTimeCode = FGlobalData::GetTimeData(TempClipData.ClipStartFrame);
EncodeVideoInfo.TrackData = TrackData;
EncodeVideoInfo.ClipData = TempClipData;
EncodeVideoInfos.Add(EncodeVideoInfo);
i++;
}

View File

@ -0,0 +1,8 @@
#include "CustomResourceCommands.h"
#define LOCTEXT_NAMESPACE "FCurtainCommands"
void FCustomResourceCommands::RegisterCommands()
{
UI_COMMAND(Delete, "删除", "Executes My FCurtainCommands", EUserInterfaceActionType::Button, FInputChord());
}
#undef LOCTEXT_NAMESPACE

View File

@ -0,0 +1,12 @@
#pragma once
class FCustomResourceCommands : public TCommands<FCustomResourceCommands>
{
public:
FCustomResourceCommands() : TCommands<FCustomResourceCommands>(TEXT("FCustomResourceCommands"), NSLOCTEXT("Contexts", "FCurtainCommands", "FCurtainCommands"), NAME_None, FAppStyle::GetAppStyleSetName())
{
}
virtual void RegisterCommands() override;
TSharedPtr<FUICommandInfo> Delete;
};

View File

@ -29,4 +29,7 @@ public:
TSharedPtr<FUICommandInfo> Copy;
TSharedPtr<FUICommandInfo> Paste;
TSharedPtr<FUICommandInfo> MicroLeft;
TSharedPtr<FUICommandInfo> MicroRight;
};

View File

@ -22,5 +22,8 @@ void FShortCutCommands::RegisterCommands()
UI_COMMAND(Copy, "复制", "Executes Start Garbage Collect", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::C, EModifierKey::Control));
UI_COMMAND(Paste, "粘贴", "Executes End Garbage Collect", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::V, EModifierKey::Control));
UI_COMMAND(MicroLeft, "左微调", "Executes My FCurtainCommands", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::Left));
UI_COMMAND(MicroRight, "右微调", "Executes My FCurtainCommands", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::Right));
}
#undef LOCTEXT_NAMESPACE

View File

@ -31,7 +31,7 @@ public:
inline static float GlobalFPS = 30.0f;
inline static FString CurrentProjectName = "DefaultProject";
inline static FString BasePath = FPaths::ProjectDir();
inline static FString Version = "1.0.0";
inline static FString Version = "1.0.1";
inline static FString ExportPath = "";
inline static TArray<FColor> Colors =
@ -97,6 +97,11 @@ struct FStringWithGUID
{
return this->Guid == Other.Guid;
}
bool operator==(const FGuid& OtherGuid) const
{
return this->Guid == OtherGuid;
}
};
enum class ETrackType
@ -168,6 +173,7 @@ struct CUT5_API FTrackData
Ar << TrackData.TrackNum;
Ar << TrackData.ClipData;
Ar << TrackData.DeviceTrack;
Ar << TrackData.IsMute;
return Ar;
};
@ -178,6 +184,8 @@ struct CUT5_API FTrackData
int32 TrackNum = 1;
FDeviceTrack DeviceTrack = FDeviceTrack("None", ETrackType::VideoTrack);
TArray<FClipData> ClipData;
bool IsMute = false;
};
struct CUT5_API FCursorData
{
@ -250,6 +258,7 @@ struct CUT5_API FPresetsCustomData
None,
Breathe,
Flash,
Gradient,
};
TArray<FLinearColor> Colors = { FLinearColor(1, 1 , 1) };
@ -920,6 +929,9 @@ struct FEncodeVideoInfo
FString EncodedVideoTimeCode = "00:00:00:00";
int32 ClipStartFrame = 0;
int32 ClipEndFrame = 0;
FTrackData TrackData;
FClipData ClipData;
};

View File

@ -14,6 +14,7 @@
#include <opencv2/videoio.hpp>
#include "AudioDevice.h"
#include "Commands/CustomResourceCommands.h"
#include "Cut5/Interface/SoundInterface.h"
#include "Cut5/Utils/FFMPEGUtils.h"
@ -259,7 +260,7 @@ void SCustomInputPanel::Construct(const FArguments& InArgs)
continue;
};
TSharedPtr<SCustomInputResource> Resource = SNew(SCustomInputResource).MainInterface(MainWidgetInterface)
TSharedPtr<SCustomInputResource> Resource = SNew(SCustomInputResource).MainInterface(MainWidgetInterface).CustomInputPanel(this)
.PropertyData(Data).OnCheckBoxChecked_Lambda([this](FTimelinePropertyData& ClickedData, bool bIsChecked)
{
if (bIsChecked == true)
@ -346,6 +347,30 @@ void SCustomInputPanel::Construct(const FArguments& InArgs)
AddPreset(TEXT("启动投影"), TEXT(""), EPresetType::EnableProjector);
AddPreset(TEXT("屏蔽投影"), TEXT(""), EPresetType::DisableProjector);
FCustomResourceCommands::Register();
CommandList = MakeShareable(new FUICommandList);
CommandList->MapAction(FCustomResourceCommands::Get().Delete, FExecuteAction::CreateLambda([this]()
{
int32 i = 0;
for (FTimelinePropertyData& TimelinePropertyData : PropertyData)
{
if (TimelinePropertyData.Guid == SelectMenuProperty)
{
PropertyData.RemoveAt(i);
break;
}
i++;
}
for (TSharedPtr<SCustomInputResource> Resource : ResourceInst)
{
if (Resource->PropertyData.Guid == SelectMenuProperty)
{
GridPanel->RemoveSlot(Resource.ToSharedRef());
break;
}
}
SelectMenuProperty.Invalidate();
}));
}
@ -361,6 +386,7 @@ FReply SCustomInputPanel::OnDrop(const FGeometry& MyGeometry, const FDragDropEve
EffectGridPanel->AddSlot(EffectGridPanel->GetChildren()->Num() % 4, EffectGridPanel->GetChildren()->Num() / 4)
[
SNew(SCustomInputResource)
.CustomInputPanel(this)
.PropertyData(Data)
.MainInterface(MainWidgetInterface)
];
@ -537,6 +563,7 @@ void SCustomInputPanel::LoadPanel(const FString& LoadPlace)
SNew(SCustomInputResource)
.PropertyData(ReloadPropertyData)
.MainInterface(MainWidgetInterface)
.CustomInputPanel(this)
];
PropertyData.Add(ReloadPropertyData);
}
@ -569,5 +596,13 @@ void SCustomInputPanel::AddCustomPreset()
}
void SCustomInputPanel::ShowMenu()
{
FMenuBuilder MenuBuilder(true, CommandList);
MenuBuilder.AddMenuEntry(FCustomResourceCommands::Get().Delete);
TSharedPtr<SWidget> MenuContent = MenuBuilder.MakeWidget();
FSlateApplication::Get().PushMenu(AsShared(), FWidgetPath(), MenuContent.ToSharedRef(), FSlateApplication::Get().GetCursorPos(), FPopupTransitionEffect::ContextMenu);
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

View File

@ -59,9 +59,15 @@ public:
bool bIsAssetPanel = false;
bool bIsEditMode = false;
TSharedPtr<FUICommandList> CommandList;
TSharedPtr<SImage> EditButton;
TSharedPtr<SImage> ImportImage;
TSharedPtr<STextBlock> ImportText;
TArray<FTimelinePropertyData> SelectedProperties;
FGuid SelectMenuProperty;
void ShowMenu();
};

View File

@ -4,7 +4,9 @@
#include "SCustomInputResource.h"
#include "DefineGlobal.h"
#include "SCustomInputPanel.h"
#include "SlateOptMacros.h"
#include "Commands/CustomResourceCommands.h"
#include "Cut5/Utils/Utils.h"
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
@ -15,6 +17,7 @@ void SCustomInputResource::Construct(const FArguments& InArgs)
VideoCapture = InArgs._VideoCapture;
OnCheckBoxChecked = InArgs._OnCheckBoxChecked;
MainInterface = InArgs._MainInterface;
CustomInputPanel = InArgs._CustomInputPanel;
ChildSlot
[
SNew(SBox)
@ -58,9 +61,18 @@ void SCustomInputResource::Construct(const FArguments& InArgs)
}
FReply SCustomInputResource::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
{
return FReply::Handled().DetectDrag(SharedThis(this), EKeys::LeftMouseButton);
}
else
{
CustomInputPanel->SelectMenuProperty = PropertyData.Guid;
CustomInputPanel->ShowMenu();
}
return FReply::Handled();
}
FReply SCustomInputResource::OnDragDetected(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{

View File

@ -20,10 +20,12 @@ public:
SLATE_ARGUMENT(cv::VideoCapture, VideoCapture)
SLATE_ARGUMENT(ICutMainWidgetInterface*, MainInterface)
SLATE_EVENT(FOnCheckBoxChecked, OnCheckBoxChecked)
SLATE_ARGUMENT(class SCustomInputPanel*, CustomInputPanel)
SLATE_END_ARGS()
/** Constructs this widget with InArgs */
FTimelinePropertyData PropertyData;
SCustomInputPanel* CustomInputPanel;
void Construct(const FArguments& InArgs);
virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
virtual FReply OnDragDetected(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;

View File

@ -372,7 +372,14 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
FShortCutCommands::Register();
const FName ContextName = FShortCutCommands::Get().GetContextName();
CommandList = MakeShared<FUICommandList>();
CommandList->MapAction(FShortCutCommands::Get().MicroLeft, FExecuteAction::CreateLambda([this]()
{
CutTimeline->AddSelectedClipsOffset(-1);
}), EUIActionRepeatMode::RepeatEnabled);
CommandList->MapAction(FShortCutCommands::Get().MicroRight, FExecuteAction::CreateLambda([this]()
{
CutTimeline->AddSelectedClipsOffset(1);
}), EUIActionRepeatMode::RepeatEnabled);
CommandList->MapAction(FShortCutCommands::Get().LeftPerFrame, FExecuteAction::CreateLambda([this]()
{
@ -859,6 +866,7 @@ void SCutMainWindow::OpenProject(const FString& Project)
CustomInputPanel->GridPanel->AddSlot(i % 2, i / 2)
[
SNew(SCustomInputResource)
.CustomInputPanel(CustomInputPanel.Get())
.PropertyData(ReloadPropertyData)
];
CustomInputPanel->PropertyData.Add(ReloadPropertyData);
@ -926,16 +934,22 @@ void SCutMainWindow::ExportProject(const FString& ExportPath)
if (ExportPath.IsEmpty())
return;
FGlobalData::ExportPath = ExportPath / FGlobalData::CurrentProjectName;
IDList.Empty();
FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*FGlobalData::ExportPath);
FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*(FGlobalData::ExportPath / "video"));
FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*(FGlobalData::ExportPath / "sound"));
FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*(FGlobalData::ExportPath / "psaf"));
FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*(FGlobalData::ExportPath / "Video"));
FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*(FGlobalData::ExportPath / "Sound"));
FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*(FGlobalData::ExportPath / "PSAF"));
tinyxml2::XMLDocument Document;
tinyxml2::XMLElement* RootElement = Document.NewElement("Project");
RootElement->SetAttribute("Name", TCHAR_TO_UTF8(*FGlobalData::CurrentProjectName));
Document.InsertFirstChild(RootElement);
tinyxml2::XMLDeclaration* decl = Document.NewDeclaration("xml version=\"1.0\"");
tinyxml2::XMLNode* XMLVersion = Document.InsertFirstChild(decl);
Document.InsertAfterChild(XMLVersion, RootElement);
tinyxml2::XMLElement* Standard = RootElement->InsertNewChildElement("Standard");
tinyxml2::XMLElement* File = Standard->InsertNewChildElement("File");
File->InsertNewChildElement("Author")->InsertNewText("Sch");
@ -966,6 +980,7 @@ void SCutMainWindow::ExportProject(const FString& ExportPath)
tinyxml2::XMLElement* PlayerLight = PlayerLightList->InsertNewChildElement("PlayerLight");
PlayerLight->InsertNewChildElement("ID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(DeviceID)));
PlayerLight->InsertNewChildElement("RoleName")->InsertNewText(TCHAR_TO_UTF8(*TrackData.DeviceTrackGroup->GroupName));
IDList.Add(TrackData.Guid, DeviceID);
DeviceID++;
}
default:
@ -984,23 +999,27 @@ void SCutMainWindow::ExportProject(const FString& ExportPath)
{
tinyxml2::XMLElement* RotationSpeaker = RoundSpeakerList->InsertNewChildElement("RotationSpeaker");
RotationSpeaker->InsertNewChildElement("ID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(DeviceID)));
RotationSpeaker->InsertNewChildElement("RoleName")->InsertNewText(TCHAR_TO_UTF8(*TrackData.DeviceName));
RotationSpeaker->InsertNewChildElement("Name")->InsertNewText(TCHAR_TO_UTF8(*TrackData.DeviceName));
DeviceID++;
IDList.Add(TrackData.Guid, DeviceID);
RotatorSpeakerIndex = DeviceID;
}
break;
case ETrackType::LightArrayTrack:
{
tinyxml2::XMLElement* LightArray = LightArrayList->InsertNewChildElement("GuangZhen");
LightArray->InsertNewChildElement("ID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(DeviceID)));
LightArray->InsertNewChildElement("RoleName")->InsertNewText(TCHAR_TO_UTF8(*TrackData.DeviceName));
LightArray->InsertNewChildElement("Name")->InsertNewText(TCHAR_TO_UTF8(*TrackData.DeviceName));
DeviceID++;
IDList.Add(TrackData.Guid, DeviceID);
LightArrayIndex = DeviceID;
}
break;
case ETrackType::ProjectorTrack:
{
tinyxml2::XMLElement* Projector = ProjectorList->InsertNewChildElement("Projector");
Projector->InsertNewChildElement("ID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(DeviceID)));
Projector->InsertNewChildElement("RoleName")->InsertNewText(TCHAR_TO_UTF8(*TrackData.DeviceName));
Projector->InsertNewChildElement("Name")->InsertNewText(TCHAR_TO_UTF8(*TrackData.DeviceName));
DeviceID++;
}
break;
@ -1008,8 +1027,17 @@ void SCutMainWindow::ExportProject(const FString& ExportPath)
{
tinyxml2::XMLElement* DMLight = DMLightList->InsertNewChildElement("DMLight");
DMLight->InsertNewChildElement("ID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(DeviceID)));
DMLight->InsertNewChildElement("RoleName")->InsertNewText(TCHAR_TO_UTF8(*TrackData.DeviceName));
DMLight->InsertNewChildElement("Name")->InsertNewText(TCHAR_TO_UTF8(*TrackData.DeviceName));
DeviceID++;
IDList.Add(TrackData.Guid, DeviceID);
}
case ETrackType::LightBarTrack:
{
tinyxml2::XMLElement* LightArray = LightArrayList->InsertNewChildElement("GuangZhen");
LightArray->InsertNewChildElement("ID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(DeviceID)));
LightArray->InsertNewChildElement("Name")->InsertNewText(TCHAR_TO_UTF8(*TrackData.DeviceName));
DeviceID++;
IDList.Add(TrackData.Guid, DeviceID);
}
default:
break;
@ -1018,7 +1046,9 @@ void SCutMainWindow::ExportProject(const FString& ExportPath)
}
tinyxml2::XMLElement* CardList = RootElement->InsertNewChildElement("CardList");
int32 CardType = 0;
tinyxml2::XMLElement* CardList = DeviceList->InsertNewChildElement("CardList");
for (int32 i = 0; i < EffectCardsPanel->EffectCardGroups.Num(); i ++)
{
if (EffectCardsPanel->EffectCardGroups[i].bIsDedicated)
@ -1027,22 +1057,68 @@ void SCutMainWindow::ExportProject(const FString& ExportPath)
{
tinyxml2::XMLElement* Card = CardList->InsertNewChildElement("Card");
Card->InsertNewChildElement("ID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(EffectCardsPanel->EffectCardGroups[i].Cards[j].ID)));
Card->InsertNewChildElement("Type")->InsertNewText(EffectCardsPanel->EffectCardGroups[i].bIsDedicated ? "0" : "2");
Card->InsertNewChildElement("Times");
Card->InsertNewChildElement("Step");
int32 TypeID = 0;
if (EffectCardsPanel->EffectCardGroups[i].Cards[j].JumpStepCurtains.Guid.IsValid())
{
TypeID = 1;
}
Card->InsertNewChildElement("Type")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(TypeID)));
Card->InsertNewChildElement("Times")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(-1)));
int32 ToStepID = 0;
if (TypeID == 1)
{
for (int32 k = 0; i < CurtainPanel->Groups.Num(); k++)
{
for (FCurtain& Curtain : CurtainPanel->Groups[k].Curtains)
{
if (Curtain.CurtainUUID == EffectCardsPanel->EffectCardGroups[i].Cards[j].JumpStepCurtains.Guid)
{
ToStepID = Curtain.Step + 1;
break;
}
}
}
}
Card->InsertNewChildElement("Step")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(ToStepID)));
Card->InsertNewChildElement("SpecialEffectID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(EffectCardsPanel->EffectCardGroups[i].Cards[j].ID)));
Card->InsertNewChildElement("SerialNumberList");
Card->InsertNewChildElement("SerialNumberList")->InsertNewChildElement("SerialNumber")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(EffectCardsPanel->EffectCardGroups[i].Cards[j].ID)));
}
}
else
{
for (int32 j = 0; j < EffectCardsPanel->EffectCardGroups[i].Cards.Num(); j++)
{
tinyxml2::XMLElement* Card = CardList->InsertNewChildElement("Card");
Card->InsertNewChildElement("ID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(EffectCardsPanel->EffectCardGroups[i].ID)));
Card->InsertNewChildElement("Type")->InsertNewText(EffectCardsPanel->EffectCardGroups[0].bIsDedicated ? "0" : "2");
Card->InsertNewChildElement("Times");
Card->InsertNewChildElement("Step");
int32 TypeID = 2;
if (EffectCardsPanel->EffectCardGroups[i].JumpStepCurtains.Guid.IsValid())
{
TypeID = 3;
}
Card->InsertNewChildElement("Type")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(TypeID)));
Card->InsertNewChildElement("Times")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(-1)));
int32 ToStepID = 0;
if (TypeID == 3)
{
for (int32 k = 0; i < CurtainPanel->Groups.Num(); k++)
{
for (FCurtain& Curtain : CurtainPanel->Groups[k].Curtains)
{
if (Curtain.CurtainUUID == EffectCardsPanel->EffectCardGroups[i].JumpStepCurtains.Guid)
{
ToStepID = Curtain.Step + 1;
break;
}
}
}
}
Card->InsertNewChildElement("Step")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(ToStepID)));
Card->InsertNewChildElement("SpecialEffectID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(EffectCardsPanel->EffectCardGroups[i].ID)));
tinyxml2::XMLElement* SerialNumberList = Card->InsertNewChildElement("SerialNumberList");
for (int32 k = 0; k < EffectCardsPanel->EffectCardGroups[i].Cards.Num(); k++)
@ -1050,12 +1126,19 @@ void SCutMainWindow::ExportProject(const FString& ExportPath)
SerialNumberList->InsertNewChildElement("SerialNumber")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(EffectCardsPanel->EffectCardGroups[i].Cards[k].ID)));
}
}
}
}
// KeyBoard
tinyxml2::XMLElement* Keyboard = RootElement->InsertNewChildElement("KeyBoard");
{
tinyxml2::XMLElement* KeyCode = Keyboard->InsertNewChildElement("KeyCode");
KeyCode->InsertNewChildElement("CTRL")->InsertNewText("");
KeyCode->InsertNewChildElement("SHIFT")->InsertNewText("");
KeyCode->InsertNewChildElement("ALT")->InsertNewText("");
KeyCode->InsertNewChildElement("KEY")->InsertNewText("");
KeyCode->InsertNewChildElement("SpecialEffectID")->InsertNewText("");
}
}
// ProcessList
tinyxml2::XMLElement* ProcessList = RootElement->InsertNewChildElement("ProcessList");
@ -1291,7 +1374,7 @@ void SCutMainWindow::AddNewCustomPreset(const FString& Name, const FPresetsCusto
NewPropertyData.PresetsCustomData = CustomData;
NewPropertyData.Name = Name;
TSharedPtr<SCustomInputResource> CustomInputResource = SNew(SCustomInputResource).PropertyData(NewPropertyData);
TSharedPtr<SCustomInputResource> CustomInputResource = SNew(SCustomInputResource).PropertyData(NewPropertyData).CustomInputPanel(CustomInputPanel.Get());
CustomInputPanel->GridPanel->AddSlot(CustomInputPanel->GridPanel->GetChildren()->Num() % 2, CustomInputPanel->GridPanel->GetChildren()->Num() / 2)
[
CustomInputResource.ToSharedRef()
@ -1342,21 +1425,35 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par
// DMLightList
tinyxml2::XMLElement* DMLightList = Light->InsertNewChildElement("DMLightList");
{
int32 j = 0;
for (int32 i = 0; i < CutTimeline->TrackGroupInstances.Num(); i++)
{
const FTrackData& TrackData = StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData;
if (TrackData.TrackType == ETrackType::SpotLightTrack)
{
tinyxml2::XMLElement* Event_List = DMLightList->InsertNewChildElement(TCHAR_TO_UTF8(*FString::Printf(TEXT("DMLight(%d)"), j)))->InsertNewChildElement("Event_List");
tinyxml2::XMLElement* DMLight = DMLightList->InsertNewChildElement(TCHAR_TO_UTF8(*FString::Printf(TEXT("DMLight"))));
DMLight->SetAttribute("ID", TCHAR_TO_UTF8(*FString::FromInt(GetTrackID(TrackData.DeviceTrack.Guid))));
tinyxml2::XMLElement* Event_List = DMLight->InsertNewChildElement("Event_List");
int32 Count = 0;
for (int32 k = 0; k < TrackData.ClipData.Num(); k++)
{
const FClipData& TempClipData = TrackData.ClipData[k];
Event_List->InsertNewChildElement("Value")->InsertNewText("1");
Event_List->InsertNewChildElement("Timecode")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::GetMsFromString(FGlobalData::GetTimeData(TempClipData.ClipStartFrame)))));
Event_List->InsertNewChildElement("Value")->InsertNewText("0");
Event_List->InsertNewChildElement("Timecode")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::GetMsFromString(FGlobalData::GetTimeData(TempClipData.ClipEndFrame)))));
tinyxml2::XMLElement* Event1 = Event_List->InsertNewChildElement("Event");
Event1->InsertNewChildElement("Value")->InsertNewText("1");
Event1->InsertNewChildElement("Timecode")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::GetMsFromString(FGlobalData::GetTimeData(TempClipData.ClipStartFrame)))));
tinyxml2::XMLElement* Event2 = Event_List->InsertNewChildElement("Event");
Event2->InsertNewChildElement("Value")->InsertNewText("0");
Event2->InsertNewChildElement("Timecode")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::GetMsFromString(FGlobalData::GetTimeData(TempClipData.ClipEndFrame)))));
Count++;
}
if (Count == 0)
{
Event_List->InsertNewText("");
}
}
}
@ -1369,8 +1466,14 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par
const FTrackData& TrackData = StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData;
if (TrackData.TrackType == ETrackType::AtomSphereLightTrack)
{
tinyxml2::XMLElement* PlayerLight = PlayerLightList->InsertNewChildElement(TCHAR_TO_UTF8(*FString::Printf(TEXT("PlayerLight(%d)"), j)));
tinyxml2::XMLElement* PlayerLight = PlayerLightList->InsertNewChildElement(TCHAR_TO_UTF8(*FString::Printf(TEXT("PlayerLight"))));
PlayerLight->SetAttribute("ID", TCHAR_TO_UTF8(*FString::FromInt(GetTrackID(TrackData.DeviceTrack.Guid))));
tinyxml2::XMLElement* SpeicalEffect = PlayerLight->InsertNewChildElement("Special_Effects_List");
if (TrackData.ClipData.Num() == 0)
{
SpeicalEffect->InsertNewText("");
}
for (int32 k = 0; k < TrackData.ClipData.Num(); k++)
{
@ -1406,12 +1509,23 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par
}
tinyxml2::XMLElement* GuangZhenList = Light->InsertNewChildElement("GuangZhenList");
{
auto GuangZhenSpecialEffectList = GuangZhenList->InsertNewChildElement("SpecialEffectList");
for (int32 k = 0; k < CutTimeline->TrackGroupInstances.Num(); k++)
{
int32 Index = 0;
const FTrackData& TrackData = StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[k].Head)->TrackData;
if (TrackData.TrackType == ETrackType::LightArrayTrack || TrackData.TrackType == ETrackType::LightBarTrack)
{
auto GuangZhen = GuangZhenList->InsertNewChildElement("GuangZhen");
GuangZhen->SetAttribute("ID", TCHAR_TO_UTF8(*FString::FromInt(GetTrackID(TrackData.DeviceTrack.Guid))));
int32 Count = 0;
auto GuangZhenSpecialEffectList = GuangZhen->InsertNewChildElement("SpecialEffectList");
for (int32 i = 0; i < CutTimeline->TrackGroupInstances.Num(); i++)
{
if (StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData.TrackType == ETrackType::LightArrayTrack)
{
TArray<FEncodeVideoInfo> EncodeVideoInfos = FUtils::ExportPsaf(StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData, *(FGlobalData::ExportPath / "psaf"));
TArray<FEncodeVideoInfo> EncodeVideoInfos = FUtils::ExportPsaf(StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData, *(FGlobalData::ExportPath / "PSAF"));
for (int32 j = 0; j < EncodeVideoInfos.Num(); j++)
{
auto SpeicalEffect = GuangZhenSpecialEffectList->InsertNewChildElement("SpeicalEffect");
@ -1433,21 +1547,29 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par
SpeicalEffectMode->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(0)));
}
}
Count++;
}
}
}
if (Count == 0)
{
GuangZhenSpecialEffectList->InsertNewText("");
}
Index++;
}
}
}
tinyxml2::XMLElement* RoomLight = Light->InsertNewChildElement("RoomLight");
{
RoomLight->InsertNewText("0");
}
tinyxml2::XMLElement* JLight = Light->InsertNewChildElement("JLight");
{
JLight->InsertNewText("0");
}
tinyxml2::XMLElement* Incense_Machine = Light->InsertNewChildElement("Incense_Machine");
{
Incense_Machine->InsertNewText("0");
}
}
}
@ -1480,6 +1602,28 @@ tinyxml2::XMLElement* SCutMainWindow::GetVideoElement(tinyxml2::XMLElement* Pare
ProjectorID->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(TempProjectorID)));
}
tinyxml2::XMLElement* VolumeEventList = Video->InsertNewChildElement("VolumeEventList");
{
tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent");
{
tinyxml2::XMLElement* VolumeEventTimeCode = VolumeEvent->InsertNewChildElement("TimeCode");
tinyxml2::XMLElement* VolumeEventValue = VolumeEvent->InsertNewChildElement("Value");
if (EncodeVideoInfo.TrackData.IsMute)
{
VolumeEventTimeCode->InsertNewText("0");
VolumeEventValue->InsertNewText("0");
}
else
{
// TODO: Dynamic Volume
VolumeEventTimeCode->InsertNewText("0");
VolumeEventValue->InsertNewText("100");
}
}
}
tinyxml2::XMLElement* ProjectorEventList = Video->InsertNewChildElement("ProjectorEventList");
{
@ -1519,6 +1663,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetVideoElement(tinyxml2::XMLElement* Pare
Value->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(ShowProjector)));
}
}
}
}
@ -1534,7 +1679,9 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundElement(tinyxml2::XMLElement* Pare
{
tinyxml2::XMLElement* Sound = Parent->InsertNewChildElement("Sound");
{
Sound->InsertNewChildElement("RotationSpeakerID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(RotatorSpeakerIndex)));
Sound->InsertNewChildElement("URL")->InsertNewText(TCHAR_TO_UTF8(*(FPaths::GetBaseFilename(EncodeVideoInfo.EncodedVideoName) + TEXT(".mp3"))));
Sound->InsertNewChildElement("Loop")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(0)));
Sound->InsertNewChildElement("Mode")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(0)));
Sound->InsertNewChildElement("Round")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(0)));
@ -1545,6 +1692,30 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundElement(tinyxml2::XMLElement* Pare
{
tinyxml2::XMLElement* VolumeEventTimeCode = VolumeEvent->InsertNewChildElement("TimeCode");
tinyxml2::XMLElement* VolumeEventValue = VolumeEvent->InsertNewChildElement("Value");
if (EncodeVideoInfo.TrackData.IsMute)
{
VolumeEventTimeCode->InsertNewText("0");
VolumeEventValue->InsertNewText("0");
}
else
{
// TODO: Dynamic Volume
VolumeEventTimeCode->InsertNewText("0");
VolumeEventValue->InsertNewText("100");
}
}
}
tinyxml2::XMLElement* RotationSpeakerEventList = Sound->InsertNewChildElement("RotationSpeakerEventList");
{
tinyxml2::XMLElement* RotationSpeakerEvent = RotationSpeakerEventList->InsertNewChildElement("RotationSpeakerEvent");
{
tinyxml2::XMLElement* RotationSpeakerEventTimeCode = RotationSpeakerEvent->InsertNewChildElement("TimeCode");
tinyxml2::XMLElement* RotationSpeakerEventValue = RotationSpeakerEvent->InsertNewChildElement("Value");
RotationSpeakerEventTimeCode->InsertNewText("0");
RotationSpeakerEventValue->InsertNewText("0");
}
}
}
@ -1554,20 +1725,26 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundElement(tinyxml2::XMLElement* Pare
tinyxml2::XMLElement* SCutMainWindow::GetVideoListElement(tinyxml2::XMLElement* Parent)
{
tinyxml2::XMLElement* VideoList = Parent->InsertNewChildElement("VideoList");
int32 Count = 0;
for (int32 i = 0; i < CutTimeline->TrackGroupInstances.Num(); i++)
{
if (StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData.TrackType == ETrackType::VideoTrack)
{
FString Filename = FGuid::NewGuid().ToString();
FString NewExportFilePath = FGlobalData::ExportPath / "video" / Filename;
FString NewExportFilePath = FGlobalData::ExportPath / "Video" / Filename;
TArray<FEncodeVideoInfo> EncodeVideoInfos = FUtils::TrackEncodeVideo(StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData, NewExportFilePath);
for (FEncodeVideoInfo EncodeVideoInfo : EncodeVideoInfos)
{
GetVideoElement(VideoList, EncodeVideoInfo);
Count++;
}
}
}
if (Count == 0)
{
VideoList->InsertNewText("");
}
return VideoList;
}
@ -1575,19 +1752,26 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundListElement(tinyxml2::XMLElement*
{
tinyxml2::XMLElement* AudioList = Parent->InsertNewChildElement("SoundList");
{
int32 Count = 0;
for (int32 i = 0; i < CutTimeline->TrackGroupInstances.Num(); i++)
{
if (StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData.TrackType == ETrackType::AudioTrack ||
StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData.TrackType == ETrackType::AudioTrackR)
{
FString Filename = FGuid::NewGuid().ToString();
FString NewExportFilePath = FGlobalData::ExportPath / "sound" / Filename;
FString NewExportFilePath = FGlobalData::ExportPath / "Sound" / Filename;
TArray<FEncodeVideoInfo> EncodeVideoInfos = FUtils::TrackEncodeAudio(StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData, NewExportFilePath);
for (FEncodeVideoInfo EncodeVideoInfo : EncodeVideoInfos)
{
GetSoundElement(AudioList, EncodeVideoInfo);
Count++;
}
}
}
if (Count == 0)
{
AudioList->InsertNewText("");
}
}
return nullptr;
@ -1609,9 +1793,9 @@ tinyxml2::XMLElement* SCutMainWindow::GetProcessB(tinyxml2::XMLElement* Parent,
{
tinyxml2::XMLElement* ProcessB = Parent->InsertNewChildElement("ProcessB");
ProcessB->SetAttribute("Name", TCHAR_TO_UTF8(*Curtain->CurtainName));
tinyxml2::XMLElement* ProcessID = ProcessB->InsertNewChildElement("ID");
tinyxml2::XMLElement* AutoNext = ProcessB->InsertNewChildElement("AutoNext");
tinyxml2::XMLElement* TimeLength = ProcessB->InsertNewChildElement("TimeLength");
ProcessB->InsertNewChildElement("ID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(Curtain->Step)));
ProcessB->InsertNewChildElement("AutoNext")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(0)));
ProcessB->InsertNewChildElement("TimeLength")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(-1)));
GetSoundListElement(ProcessB);
ProcessB->InsertEndChild(GetDeviceElement(ProcessB));
@ -1620,14 +1804,48 @@ tinyxml2::XMLElement* SCutMainWindow::GetProcessB(tinyxml2::XMLElement* Parent,
// 非必须项
tinyxml2::XMLElement* Identity_SpecialEffects = ProcessB->InsertNewChildElement("Identity_SpecialEffects");
{
Identity_SpecialEffects->InsertNewText("");
}
tinyxml2::XMLElement* IsGlobal = ProcessB->InsertNewChildElement("IsGlobal");
{
IsGlobal->InsertNewText("1");
}
tinyxml2::XMLElement* State = ProcessB->InsertNewChildElement("State");
{
State->InsertNewText("");
}
tinyxml2::XMLElement* EnableCard = ProcessB->InsertNewChildElement("EnableCard");
{
int32 Count = 0;
for (int32 i = 0; i < EffectCardsPanel->EffectCardGroups.Num(); i++)
{
if (!EffectCardsPanel->EffectCardGroups[i].bIsDedicated)
{
if (EffectCardsPanel->EffectCardGroups[i].UsedCurtains.Contains(Curtain->CurtainUUID))
{
tinyxml2::XMLElement* SerialNumber = EnableCard->InsertNewChildElement("SerialNumber");
SerialNumber->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(EffectCardsPanel->EffectCardGroups[i].ID)));
Count++;
}
continue;
}
for (int32 j = 0 ; j < EffectCardsPanel->EffectCardGroups[i].Cards.Num(); j++)
{
if (EffectCardsPanel->EffectCardGroups[i].Cards[j].UsedCurtains.Contains(Curtain->CurtainUUID))
{
tinyxml2::XMLElement* SerialNumber = EnableCard->InsertNewChildElement("SerialNumber");
SerialNumber->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(EffectCardsPanel->EffectCardGroups[i].Cards[j].ID)));
Count++;
}
}
}
if (Count == 0)
{
EnableCard->InsertNewText("");
}
}
return ProcessB;
@ -1641,12 +1859,8 @@ tinyxml2::XMLElement* SCutMainWindow::GetSpecialEffectList(tinyxml2::XMLElement*
{
if (!EffectCardsPanel->EffectCardGroups[i].bIsDedicated)
{
if (EffectCardsPanel->EffectCardGroups[i].bIsDedicated == false)
{
const FString Name = FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, TEXT("FX"), EffectCardsPanel->EffectCardGroups[i].GroupName + TEXT(".bin"));
OpenTimeline(Name, true, true);
OpenTimeline(FUtils::GroupFullPath(EffectCardsPanel->EffectCardGroups[i].Guid.ToString()), true, true);
CurrentSelectedPropertiesInterfaceGuid = EffectCardsPanel->EffectCardGroups[i].Guid;
}
GetSpecialEffectGroup(SpecialEffectsList, &EffectCardsPanel->EffectCardGroups[i]);
SpecialEffectID++;
continue;
@ -1661,6 +1875,11 @@ tinyxml2::XMLElement* SCutMainWindow::GetSpecialEffectList(tinyxml2::XMLElement*
SpecialEffectID++;
}
if (SpecialEffectID == 0)
{
SpecialEffectsList->InsertNewText("");
}
return SpecialEffectsList;
}
@ -1675,6 +1894,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetSpecialEffectGroup(tinyxml2::XMLElement
ID->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(Group->ID)));
}
tinyxml2::XMLElement* AutoNext = Effect->InsertNewChildElement("AutoNext");
AutoNext->InsertNewText("0");
GetSoundListElement(Effect);
GetDeviceElement(Effect);
GetVideoListElement(Effect);
@ -1686,7 +1906,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetSpecialEffectGroup(tinyxml2::XMLElement
}
tinyxml2::XMLElement* State = Effect->InsertNewChildElement("State");
{
State->InsertNewText("0");
}
return Effect;
}
@ -1702,24 +1922,8 @@ tinyxml2::XMLElement* SCutMainWindow::GetSpecialEffect(tinyxml2::XMLElement* Par
ID->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(Effect->ID)));
}
int32 CardType = 0;
if (Effect->JumpStepCurtains.Guid.IsValid())
{
CardType = 1;
}
Effectxml->InsertNewChildElement("Type")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(CardType)));
Effectxml->InsertNewChildElement("Times")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(-1)));
int32 Step = 0;
for (int32 i = 0; i < CurtainPanel->Groups.Num(); i++)
{
}
Effectxml->InsertNewChildElement("Step")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(Step)));
tinyxml2::XMLElement* AutoNext = Effectxml->InsertNewChildElement("AutoNext");
AutoNext->InsertNewText("0");
GetSoundListElement(Effectxml);
GetDeviceElement(Effectxml);
GetVideoListElement(Effectxml);
@ -1731,10 +1935,17 @@ tinyxml2::XMLElement* SCutMainWindow::GetSpecialEffect(tinyxml2::XMLElement* Par
}
tinyxml2::XMLElement* State = Effectxml->InsertNewChildElement("State");
{
State->InsertNewText("0");
}
return Effectxml;
}
int32 SCutMainWindow::GetTrackID(FGuid Guid) const
{
const int32* Index = IDList.Find(Guid);
const int32 NewIndex = Index != nullptr ? *Index : -1;
return NewIndex;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

View File

@ -108,6 +108,12 @@ public:
tinyxml2::XMLElement* GetSpecialEffectList(tinyxml2::XMLElement* Parent);
tinyxml2::XMLElement* GetSpecialEffectGroup(tinyxml2::XMLElement* Parent, FEffectCardGroup* Group);
tinyxml2::XMLElement* GetSpecialEffect(tinyxml2::XMLElement* Parent, FEffectCardProperty* Effect);
int32 RotatorSpeakerIndex = 0;
int32 LightArrayIndex = 0;
TMap<FGuid, int32> IDList = {};
int32 GetTrackID(FGuid Guid) const;
};

View File

@ -188,7 +188,7 @@ void SCutTimeline::Construct(const FArguments& InArgs)
.OnValueChanged_Lambda([this](float ChangedValue)
{
FGlobalData::DefaultTimeTickSpace = FMath::GetMappedRangeValueClamped(FVector2D(0, 1.0), FVector2D(GetCachedGeometry().GetLocalSize().X / FGlobalData::TrackLength, 14), ChangedValue);
UpdateCursorPosition(GetCursorPosition());
RenderGroup();
})
]
@ -218,7 +218,7 @@ void SCutTimeline::Construct(const FArguments& InArgs)
[
SNew(SBox)
.WidthOverride(10000)
.HeightOverride(25)
.HeightOverride(40)
// 刻度补差值
]
+ SVerticalBox::Slot()
@ -242,7 +242,7 @@ void SCutTimeline::Construct(const FArguments& InArgs)
[
SNew(SBox)
.WidthOverride(10000)
.HeightOverride(25)
.HeightOverride(40)
// 刻度补差值
]
+ SVerticalBox::Slot()
@ -266,7 +266,7 @@ void SCutTimeline::Construct(const FArguments& InArgs)
[
SAssignNew(TimelineTickBox, SBox)
.WidthOverride(FGlobalData::TrackLength * FGlobalData::DefaultTimeTickSpace)
.MaxDesiredHeight(60)
.HeightOverride(40)
[
SAssignNew(TickScrollBox, SScrollBox)
.ScrollBarVisibility(EVisibility::Hidden)
@ -790,6 +790,69 @@ void SCutTimeline::AddNewDeviceToGroup(FString GroupName, FDeviceTrack DeviceTra
{
MainWidgetInterface->OnAddNewTrack(ETrackType::PlayerTrack);
}
}
void SCutTimeline::AddSelectedClipsOffset(int32 FrameOffset)
{
TArray<FClipData*> NewSelectedClipData;
for (int32 i = 0; i < TrackGroupInstances.Num(); i++)
{
for (FClipData& TempClipData : StaticCastSharedPtr<STrackHead>(TrackGroupInstances[i].Head)->TrackData.ClipData)
{
if (SelectedClips.Contains(TempClipData.ClipGuid))
{
NewSelectedClipData.Add(&TempClipData);
}
}
}
int32 MinFrame = FGlobalData::TrackLength;
for (FClipData* ClipData : NewSelectedClipData)
{
if (ClipData->ClipStartFrame < MinFrame)
{
MinFrame = ClipData->ClipStartFrame;
}
}
int32 MaxFrame = 0;
for (FClipData* ClipData : NewSelectedClipData)
{
if (ClipData->ClipEndFrame > MaxFrame)
{
MaxFrame = ClipData->ClipEndFrame;
}
}
if (FrameOffset > 0)
{
if (MinFrame >= 0 && MaxFrame < FGlobalData::TrackLength)
{
for (FClipData* ClipData : NewSelectedClipData)
{
ClipData->ClipStartFrame += FrameOffset;
ClipData->ClipEndFrame += FrameOffset;
}
RenderGroup();
}
}
else if (FrameOffset < 0)
{
if (MinFrame > 0 && MaxFrame < FGlobalData::TrackLength)
{
for (FClipData* ClipData : NewSelectedClipData)
{
ClipData->ClipStartFrame += FrameOffset;
ClipData->ClipEndFrame += FrameOffset;
}
RenderGroup();
}
}
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

View File

@ -134,6 +134,9 @@ public:
TArray<FVector2D> RenderBoxPos {{}, {}};
bool bNeedShowPanel = false;
void AddSelectedClipsOffset(int32 FrameOffset);
};

View File

@ -19,9 +19,12 @@
#include "DragDropOperator/DragDropOperator.h"
#include "Engine/Engine.h"
#include "Engine/Texture2D.h"
#include "MicroWidgets/SNewProjectTips.h"
#include "Presets/SClipCursor.h"
#include "Rendering/DrawElementPayloads.h"
#include "Slate/Private/Framework/Application/Menu.h"
#include "Widgets/Input/SSpinBox.h"
#include "Widgets/Layout/SSpacer.h"
extern "C"
{
@ -58,11 +61,15 @@ FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const F
}
MainWidgetInterface->GetCutTimeline()->SelectedClips.AddUnique(ClipData->ClipGuid);
MainWidgetInterface->UpdateProperties(nullptr);
MainWidgetInterface->UpdateProperties(this);
LocalPos = Geometry.AbsoluteToLocal(PointerEvent.GetScreenSpacePosition());
const float DragOffset = MainWidgetInterface->GetCutTimeline()->GetCachedGeometry().AbsoluteToLocal(PointerEvent.GetScreenSpacePosition()).X;
if (LocalPos.X <= 10)
{
if (ClipData->bCanDrag && !MainWidgetInterface->GetCutTimeline()->SelectedClips.Contains(ClipData->ClipGuid))
if (ClipData->bCanDrag && (!MainWidgetInterface->GetCutTimeline()->SelectedClips.Contains(ClipData->ClipGuid) || MainWidgetInterface->GetCutTimeline()->SelectedClips.Num() == 1))
{
const TSharedPtr<FClip2ClipDragDropOperation> Clip2ClipDragDropOperation = MakeShared<FClip2ClipDragDropOperation>();
Clip2ClipDragDropOperation->TrackBody = StaticCastSharedPtr<STrackBody>(Body);
@ -77,7 +84,7 @@ FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const F
}
if (LocalPos.X >= Geometry.GetLocalSize().X - 10)
{
if (ClipData->bCanDrag && !MainWidgetInterface->GetCutTimeline()->SelectedClips.Contains(ClipData->ClipGuid))
if (ClipData->bCanDrag && (!MainWidgetInterface->GetCutTimeline()->SelectedClips.Contains(ClipData->ClipGuid) || MainWidgetInterface->GetCutTimeline()->SelectedClips.Num() == 1))
{
const TSharedPtr<FClip2ClipDragDropOperation> Clip2ClipDragDropOperation = MakeShared<FClip2ClipDragDropOperation>();
Clip2ClipDragDropOperation->TrackBody = StaticCastSharedPtr<STrackBody>(Body);
@ -679,6 +686,10 @@ void STimelineClip::UpdateMove(int32 X, int32 DragOffset)
FReply STimelineClip::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
LocalPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
TSharedPtr<STrackBody> NewBody = StaticCastSharedPtr<STrackBody>(Body);
bNeedPaintDrag = false;
if (LocalPos.X <= 10)
{
@ -693,9 +704,14 @@ FReply STimelineClip::OnMouseMove(const FGeometry& MyGeometry, const FPointerEve
if (MainWidgetInterface->GetSelectedMode() == ESelectMode::CutMode)
{
float Pos = NewBody->GetCachedGeometry().AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()).X / FGlobalData::DefaultTimeTickSpace;
MainWidgetInterface->GetCutTimeline()->CurrentTimeData->SetText(FText::FromString(FGlobalData::GetTimeData(Pos) + " / "));
bNeedPaintDrag = true;
PaintDragType = 2;
}
return FReply::Handled();
}
@ -863,6 +879,9 @@ FReply STimelineClip::OnDragOver(const FGeometry& MyGeometry, const FDragDropEve
void STimelineClip::DoSound(ESoundSolveType SolveType, int32 InFrame)
{
TSharedPtr<STrackBody> NewBody = StaticCastSharedPtr<STrackBody>(Body);
if (NewBody->TrackHead->TrackData.IsMute)
return;
if (SoundThread == nullptr)
{
if (ClipData->ResourcePropertyDataPtr == nullptr)
@ -982,5 +1001,256 @@ void STimelineClip::Tick(const FGeometry& AllottedGeometry, const double InCurre
}
}
TSharedPtr<SWidget> STimelineClip::GetPropertiesWidget()
{
Selectable.Empty();
Selectable.Add(MakeShared<FString>(TEXT("")));
Selectable.Add(MakeShared<FString>(TEXT("呼吸")));
Selectable.Add(MakeShared<FString>(TEXT("闪烁")));
Selectable.Add(MakeShared<FString>(TEXT("渐变")));
FTextBlockStyle NormalText = FAppStyle::GetWidgetStyle<FTextBlockStyle>("NormalText");
NormalText.SetFontSize(13);
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_Lambda([this]()
{
if (CustomData.Colors.Num() == 0)
{
return FLinearColor(1, 1, 1, 0.5);
}
return CustomData.Colors[0];
})
.OnMouseButtonDown_Lambda([this](const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
MainWidgetInterface->OpenColorPanel(&CustomData.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:
CustomData.PresetCustomType = FPresetsCustomData::EPresetCustomType::None;
break;
case 1:
CustomData.PresetCustomType = FPresetsCustomData::EPresetCustomType::Breathe;
break;
case 2:
CustomData.PresetCustomType = FPresetsCustomData::EPresetCustomType::Flash;
break;
case 3:
CustomData.PresetCustomType = FPresetsCustomData::EPresetCustomType::Gradient;
default:
break;
}
})
[
SNew(STextBlock)
.Text_Lambda([this]()
{
return FText::FromString( CustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::None ? TEXT("") : CustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Breathe ? TEXT("呼吸") : TEXT("闪烁"));
})
]
]
]
]
]
+ 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<int32>)
.Value(1)
.MinValue(1)
.OnValueChanged_Lambda([this](const int32& Value)
{
CustomData.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)
{
CustomData.Time = Value;
})
// .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)
{
MainWidgetInterface->AddNewCustomPreset(String, CustomData);
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)
]
]
];
// TODO: 配置文件保存自定义效果
// TODO: 自定义效果拖拽到轨道
return PropertiesWidget;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

View File

@ -10,6 +10,7 @@
#include "Cut5/Interface/SoundInterface.h"
#include "Widgets/Input/SComboBox.h"
#include "Widgets/Layout/SBox.h"
extern "C"
{
@ -21,7 +22,7 @@ extern "C"
/**
*
*/
class CUT5_API STimelineClip : public SCompoundWidget
class CUT5_API STimelineClip : public SCompoundWidget, public IPropertiesInterface
{
public:
SLATE_BEGIN_ARGS(STimelineClip)
@ -72,5 +73,11 @@ public:
FTimelinePropertyData ThumbnailCodecContext;
virtual TSharedPtr<SWidget> GetPropertiesWidget() override;
TSharedPtr<SComboBox<TSharedPtr<FString>>> GroupComboBox;
TArray<TSharedPtr<FString>> Selectable;
FPresetsCustomData CustomData;
};

View File

@ -31,7 +31,7 @@ void STrackHead::Construct(const FArguments& InArgs)
}));
}));
TSharedPtr<SImage> Image = SNew(SImage);
Image = SNew(SImage);
ChildSlot
[
SNew(SBox)
@ -103,6 +103,11 @@ void STrackHead::Construct(const FArguments& InArgs)
FSlateDynamicImageBrush* Brush = new FSlateDynamicImageBrush(*(ImagePath), FVector2D(48, 48));
Image->SetImage(Brush);
if (TrackData.TrackType == ETrackType::VideoTrack || TrackData.TrackType == ETrackType::AudioTrackR || TrackData.TrackType == ETrackType::AudioTrack)
{
Image->SetColorAndOpacity(TrackData.IsMute ? FLinearColor(1, 0.5, 0.5, 1) : FLinearColor(1, 1, 1, 1));
}
}
FReply STrackHead::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
@ -113,7 +118,15 @@ FReply STrackHead::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointer
MenuBuilder.AddMenuEntry(FTimelineTrackCommands::Get().Remove);
FSlateApplication::Get().PushMenu(AsShared(), FWidgetPath(), MenuBuilder.MakeWidget(), FSlateApplication::Get().GetCursorPos(), FPopupTransitionEffect(FPopupTransitionEffect::ContextMenu));
}
//
if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
{
if (TrackData.TrackType == ETrackType::VideoTrack || TrackData.TrackType == ETrackType::AudioTrackR || TrackData.TrackType == ETrackType::AudioTrack)
{
TrackData.IsMute = !TrackData.IsMute;
Image->SetColorAndOpacity(TrackData.IsMute ? FLinearColor(1, 0.5, 0.5, 1) : FLinearColor(1, 1, 1, 1));
}
}
return FReply::Unhandled();
}

View File

@ -27,9 +27,10 @@ public:
FTrackData TrackData;
TSharedPtr<SCutTimeline> CutTimeline;
TSharedPtr<SImage> Image;
ICutMainWidgetInterface* MainWidgetInterface;
FString GroupName;
virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
bool bIsMute = false;
TSharedPtr<FUICommandList> CommandList;
};