From 3cf55af0c7de1726c811c035e0f32c2ffb07db9f Mon Sep 17 00:00:00 2001 From: Sch <3516520171@qq.com> Date: Wed, 20 Sep 2023 17:55:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=80=E8=BF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Plugins/SchUtils/Resources/Icon128.png | Bin 0 -> 12699 bytes Plugins/SchUtils/SchUtils.uplugin | 24 + .../Source/SchUtils/Private/SchUtils.cpp | 121 ++++ .../Source/SchUtils/Public/SchUtils.h | 75 ++ .../Source/SchUtils/SchUtils.Build.cs | 53 ++ Source/Cut5/Cut5.Build.cs | 4 +- .../Cut5/Interface/CutMainWidgetInterface.h | 1 + Source/Cut5/Interface/ExportThread.cpp | 85 +++ Source/Cut5/Interface/ExportThread.h | 27 + Source/Cut5/Interface/VideoInterface.cpp | 32 + Source/Cut5/Utils/CutPlatformUtils.cpp | 13 +- Source/Cut5/Utils/Utils.cpp | 136 ++-- .../Widgets/Commands/TimelineClipCommands.cpp | 1 + .../Widgets/Commands/TimelineClipCommands.h | 1 + Source/Cut5/Widgets/Curtain/SCurtain.cpp | 66 ++ Source/Cut5/Widgets/Curtain/SCurtain.h | 6 +- Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp | 1 + Source/Cut5/Widgets/DefineGlobal.h | 8 +- .../DragDropOperator/DragDropOperator.cpp | 9 +- Source/Cut5/Widgets/FX/SEffectCard.cpp | 41 ++ Source/Cut5/Widgets/FX/SEffectCardGroup.cpp | 62 +- Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp | 67 +- Source/Cut5/Widgets/FX/SEffectCardsPanel.h | 4 + .../Cut5/Widgets/MicroWidgets/SColorPanel.cpp | 2 + .../Cut5/Widgets/MicroWidgets/SColorPanel.h | 3 + Source/Cut5/Widgets/SCustomInputPanel.cpp | 6 +- Source/Cut5/Widgets/SCutMainWindow.cpp | 396 ++++++++-- Source/Cut5/Widgets/SCutMainWindow.h | 43 +- Source/Cut5/Widgets/SCutTimeline.cpp | 9 +- Source/Cut5/Widgets/SCutTimeline.h | 6 +- Source/Cut5/Widgets/STimelineClip.cpp | 174 +++-- Source/Cut5/Widgets/STrackBody.cpp | 33 + Source/Cut5/Widgets/STrackBody.h | 2 + .../Widgets/StatePanel/SLightArrayPanel.cpp | 26 + .../Widgets/StatePanel/SLightArrayPanel.h | 1 + .../StaticProperties/ClipProperties.cpp | 674 ++++++++++++++++++ .../Widgets/StaticProperties/ClipProperties.h | 16 + .../Cut5/Widgets/TimelineClips/ClipProxy.cpp | 24 +- 38 files changed, 2021 insertions(+), 231 deletions(-) create mode 100644 Plugins/SchUtils/Resources/Icon128.png create mode 100644 Plugins/SchUtils/SchUtils.uplugin create mode 100644 Plugins/SchUtils/Source/SchUtils/Private/SchUtils.cpp create mode 100644 Plugins/SchUtils/Source/SchUtils/Public/SchUtils.h create mode 100644 Plugins/SchUtils/Source/SchUtils/SchUtils.Build.cs create mode 100644 Source/Cut5/Interface/ExportThread.cpp create mode 100644 Source/Cut5/Interface/ExportThread.h create mode 100644 Source/Cut5/Widgets/StaticProperties/ClipProperties.cpp create mode 100644 Source/Cut5/Widgets/StaticProperties/ClipProperties.h diff --git a/Plugins/SchUtils/Resources/Icon128.png b/Plugins/SchUtils/Resources/Icon128.png new file mode 100644 index 0000000000000000000000000000000000000000..1231d4aad4d0d462fb7b178eb5b30aa61a10df0b GIT binary patch literal 12699 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 a;7#~yJh_ha>A&A^fRdb=Y>l)<=>Gxy=2LS3 literal 0 HcmV?d00001 diff --git a/Plugins/SchUtils/SchUtils.uplugin b/Plugins/SchUtils/SchUtils.uplugin new file mode 100644 index 0000000..2e14fb4 --- /dev/null +++ b/Plugins/SchUtils/SchUtils.uplugin @@ -0,0 +1,24 @@ +{ + "FileVersion": 3, + "Version": 1, + "VersionName": "1.0", + "FriendlyName": "SchUtils", + "Description": "https://space.bilibili.com/234305886", + "Category": "Other", + "CreatedBy": "Sch", + "CreatedByURL": "", + "DocsURL": "", + "MarketplaceURL": "", + "SupportURL": "", + "CanContainContent": true, + "IsBetaVersion": false, + "IsExperimentalVersion": false, + "Installed": false, + "Modules": [ + { + "Name": "SchUtils", + "Type": "Runtime", + "LoadingPhase": "Default" + } + ] +} \ No newline at end of file diff --git a/Plugins/SchUtils/Source/SchUtils/Private/SchUtils.cpp b/Plugins/SchUtils/Source/SchUtils/Private/SchUtils.cpp new file mode 100644 index 0000000..545fc16 --- /dev/null +++ b/Plugins/SchUtils/Source/SchUtils/Private/SchUtils.cpp @@ -0,0 +1,121 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "SchUtils.h" + +#define LOCTEXT_NAMESPACE "FSchUtilsModule" + +void FSchUtilsModule::OnSchDebugCommand(const TArray& Strings) +{ + if (Strings.Num() == 0) + { + UE_LOG(LogTemp, Warning, TEXT("SchDebug: No Args")); + return; + } + if (Strings.Num() == 1) + { + LogValue(Strings[0]); + } + if (Strings.Num() == 2) + { + SetDebugValue(Strings[0], Strings[1]); + } +} + +void FSchUtilsModule::StartupModule() +{ + // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module + + // Register Debug Console Commands + IConsoleManager::Get().RegisterConsoleCommand(TEXT("SchDebugMode"), TEXT("Set Debug Mode, 1 for Draw Screen, 2 for UE LOG, UE LOG Default!") + , FConsoleCommandWithArgsDelegate::CreateLambda([](const TArray& Args) + { + + })); + + IConsoleManager::Get().RegisterConsoleCommand( + TEXT("SchDebug"), TEXT("Debug Tool for Debug Marco"), + FConsoleCommandWithArgsDelegate::CreateRaw(this, &FSchUtilsModule::OnSchDebugCommand), ECVF_Default); +} + +void FSchUtilsModule::ShutdownModule() +{ + // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, + // we call this function before unloading the module. + + TArray Keys; + DebugOffsetMap.GetKeys(Keys); + for (FString Str : Keys) + { + delete[] DebugOffsetMap[Str].Data; + } +} + +void FSchUtilsModule::LogValue(const FString& Name) +{ + switch (DebugOffsetMap[Name].Type) + { + case EDebugToolDataType::Float: + { + UE_LOG(LogTemp, Warning, TEXT("SchDebug: %s = %f"), *Name, *reinterpret_cast(DebugOffsetMap[Name].Data)); + break; + } + case EDebugToolDataType::Int32: + { + UE_LOG(LogTemp, Warning, TEXT("SchDebug: %s = %d"), *Name, *reinterpret_cast(DebugOffsetMap[Name].Data)); + break; + } + case EDebugToolDataType::Vector: + { + UE_LOG(LogTemp, Warning, TEXT("SchDebug: %s = %s"), *Name, *reinterpret_cast(DebugOffsetMap[Name].Data)->ToString()) + + + + break; + } + default: + { + // UE_LOG(LogTemp, Warning, TEXT("SchDebug: %s = %s"), *Name, *reinterpret_cast(DebugOffsetMap[Name].Data)); + + break; + } + } +} + +void FSchUtilsModule::SetDebugValue(const FString& Name, const FString& Value) +{ + switch (DebugOffsetMap[Name].Type) + { + case EDebugToolDataType::Float: + { + *reinterpret_cast(DebugOffsetMap[Name].Data) = FCString::Atof(*Value); + break; + } + case EDebugToolDataType::Int32: + { + *reinterpret_cast(DebugOffsetMap[Name].Data) = FCString::Atoi(*Value); + break; + } + case EDebugToolDataType::Vector: + { + *reinterpret_cast(DebugOffsetMap[Name].Data) = FVector::ZeroVector; + break; + } + default: + { + *reinterpret_cast(DebugOffsetMap[Name].Data) = Value; + break; + } + } +} + +void FSchUtilsModule::LogOpts(const FString& Name) +{ + if (Name == "1" || Name == "2") + { + CurrentLogOpts = FCString::Atoi(*Name); + } +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FSchUtilsModule, SchUtils) \ No newline at end of file diff --git a/Plugins/SchUtils/Source/SchUtils/Public/SchUtils.h b/Plugins/SchUtils/Source/SchUtils/Public/SchUtils.h new file mode 100644 index 0000000..ee41490 --- /dev/null +++ b/Plugins/SchUtils/Source/SchUtils/Public/SchUtils.h @@ -0,0 +1,75 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Modules/ModuleManager.h" + +#ifdef UE_BUILD_SHIPPING +#define SCH_DEBUG_FLOAT(x, Name) x +#define SCH_DEBUG_INT32(x, Name) x +#define SCH_DEBUG_Vector(x, Name) x +#elif +#define SCH_DEBUG_FLOAT(x, Name) FSchUtilsModule::DebugValue(x, L##Name, EDebugToolDataType::Float) +#define SCH_DEBUG_INT32(x, Name) FSchUtilsModule::DebugValue(x, L##Name, EDebugToolDataType::Int32) +#define SCH_DEBUG_Vector(x, Name) FSchUtilsModule::DebugValue(x, L##Name, EDebugToolDataType::Vector) +#endif + +#define SCH_LOG_OPTS(x) FSchUtilsModule::LogOpts(x) + +enum class EDebugToolDataType +{ + Float, + Int32, + Vector, +}; + +struct FDebugToolsByteOffsetStruct +{ + FDebugToolsByteOffsetStruct(uint8* Data, EDebugToolDataType Type) + : Type(Type) + , Data(Data) + { + } + EDebugToolDataType Type; + uint8* Data; + +}; + +class FSchUtilsModule : public IModuleInterface +{ +public: + void OnSchDebugCommand(const TArray& Strings); + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; + + template + inline static Type DebugValue(Type Value, const FString& Name, EDebugToolDataType TypeEnum); + inline static void LogValue(const FString& Name); + inline static void SetDebugValue(const FString& Name, const FString& Value); + inline static void LogOpts(const FString& Name); + + + inline static TMap DebugOffsetMap; + + inline static int32 CurrentLogOpts = 2; +}; + + + +template +Type FSchUtilsModule::DebugValue(Type Value, const FString& Name, EDebugToolDataType TypeEnum) +{ + if (DebugOffsetMap.Contains(Name)) + { + return *reinterpret_cast(DebugOffsetMap[Name].Data); + } + else + { + uint8* NewValue = new uint8[sizeof(Type)]; + *reinterpret_cast(NewValue) = Value; + DebugOffsetMap[Name] = FDebugToolsByteOffsetStruct(NewValue, TypeEnum); + } + return Type(); +} diff --git a/Plugins/SchUtils/Source/SchUtils/SchUtils.Build.cs b/Plugins/SchUtils/Source/SchUtils/SchUtils.Build.cs new file mode 100644 index 0000000..dfd8b4c --- /dev/null +++ b/Plugins/SchUtils/Source/SchUtils/SchUtils.Build.cs @@ -0,0 +1,53 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class SchUtils : ModuleRules +{ + public SchUtils(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicIncludePaths.AddRange( + new string[] { + // ... add public include paths required here ... + } + ); + + + PrivateIncludePaths.AddRange( + new string[] { + // ... add other private include paths required here ... + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + // ... add other public dependencies that you statically link with here ... + } + ); + + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + "Slate", + "SlateCore", + // ... add private dependencies that you statically link with here ... + } + ); + + + DynamicallyLoadedModuleNames.AddRange( + new string[] + { + // ... add any modules that your module loads dynamically here ... + } + ); + } +} diff --git a/Source/Cut5/Cut5.Build.cs b/Source/Cut5/Cut5.Build.cs index 22b593a..da892b3 100644 --- a/Source/Cut5/Cut5.Build.cs +++ b/Source/Cut5/Cut5.Build.cs @@ -12,9 +12,9 @@ public class Cut5 : ModuleRules { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; - PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" , "FFMPEGMedia", "FFMPEGMediaFactory"}); + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" , "FFMPEGMedia", "FFMPEGMediaFactory", "SchUtils"}); PrivateDependencyModuleNames.AddRange(new string[] {"ApplicationCore", "FFMPEGMedia", "FFMPEGMediaFactory", - "Slate", "SlateCore", "UMG", "OpenCV", "DesktopPlatform", "PortAudioPlugin"}); + "Slate", "SlateCore", "UMG", "OpenCV", "DesktopPlatform", "PortAudioPlugin", "SchUtils"}); } } diff --git a/Source/Cut5/Interface/CutMainWidgetInterface.h b/Source/Cut5/Interface/CutMainWidgetInterface.h index a7fc78c..f404153 100644 --- a/Source/Cut5/Interface/CutMainWidgetInterface.h +++ b/Source/Cut5/Interface/CutMainWidgetInterface.h @@ -30,6 +30,7 @@ public: virtual void OnUpdateLightArray(const TArray& LightArray) {}; virtual void OnUpdateSpotLight(int32 Index, FColor LightColor) {}; virtual void OnUpdateProjector(int32 Index, bool bEnableProjector) {}; + virtual void OnUpdateLightBar(const TArray& LightArray) {}; virtual void OnUpdatePlayers(TSharedPtr TrackBody, FColor PlayerColor) {}; virtual void OnAddNewTrack(ETrackType Type) {}; diff --git a/Source/Cut5/Interface/ExportThread.cpp b/Source/Cut5/Interface/ExportThread.cpp new file mode 100644 index 0000000..8edb7d9 --- /dev/null +++ b/Source/Cut5/Interface/ExportThread.cpp @@ -0,0 +1,85 @@ +#include "ExportThread.h" + +#include + +void FExportThread::Stop() +{ + bNeedClose = true; + FRunnable::Stop(); +} + +bool FExportThread::Init() +{ + ProcessWindow = ::CreateWindowExW(WS_EX_TOPMOST, WC_DIALOG, L"进度...", 0, CW_USEDEFAULT, CW_USEDEFAULT, 300, 100, + NULL, NULL, NULL, NULL); + if (ProcessWindow) + { + RECT rcClient; + GetClientRect(ProcessWindow, &rcClient); + + + + ProcessBar = ::CreateWindowExW(0, PROGRESS_CLASS, NULL, + WS_CHILD | WS_VISIBLE, 0, 0, rcClient.right, rcClient.bottom, ProcessWindow, NULL, NULL, NULL); + + ProcessText = ::CreateWindowExW(0, WC_STATIC, NULL, WS_CHILD | WS_VISIBLE | SS_CENTER, 0, 0, rcClient.right, rcClient.bottom, ProcessBar, NULL, NULL, NULL); + SubProcessText = ::CreateWindowExW(0, WC_STATIC, NULL, WS_CHILD | WS_VISIBLE | SS_CENTER, 0, 50, rcClient.right, rcClient.bottom, ProcessBar, NULL, NULL, NULL); + + ::ShowWindow(ProcessWindow, SW_SHOW); + + } + return FRunnable::Init(); +} + +uint32 FExportThread::Run() +{ + int32 LastPercent = 0; + int32 LastMaxPercent = 0; + ::SendMessageW(ProcessBar, PBM_SETRANGE, 0, MAKELPARAM(0, MaxPercent)); + ::SendMessageW(ProcessBar, PBM_SETPOS, 3, 0); + while (!bNeedClose) + { + + + if (LastPercent != CurrentPercent || LastMaxPercent != MaxPercent) + { + LastPercent = CurrentPercent; + LastMaxPercent = MaxPercent; + ::SetWindowTextW(ProcessText, *FString::Printf(TEXT("进度:%d/%d"), int32(CurrentPercent), int32(MaxPercent))); + ::SetWindowTextW(SubProcessText, *FString::Printf(TEXT("子进度:%d/%d"), int32(SubCurrentPercent), int32(SubMaxPercent))); + } + + const LPMSG MSG = {nullptr}; + while (PeekMessageW(MSG, ProcessWindow, 0, 0, PM_REMOVE)) + { + TranslateMessage(MSG); + DispatchMessageW(MSG); + + switch (MSG->message) + { + case WM_CLOSE: + { + bNeedClose = true; + PostQuitMessage(0); + break; + } + case WM_DESTROY: + bNeedClose = true; + DestroyWindow(0); + default: + break; + + } + } + // ::UpdateWindow(ProcessWindow); + + ::BringWindowToTop(ProcessWindow); + } + return 0; +} + +void FExportThread::Exit() +{ + ::DestroyWindow(ProcessWindow); + FRunnable::Exit(); +} diff --git a/Source/Cut5/Interface/ExportThread.h b/Source/Cut5/Interface/ExportThread.h new file mode 100644 index 0000000..f0eaeda --- /dev/null +++ b/Source/Cut5/Interface/ExportThread.h @@ -0,0 +1,27 @@ +#pragma once +#include "Windows/AllowWindowsPlatformTypes.h" +#include "Windows/PreWindowsApi.h" +#include "Windows/MinWindows.h" +#include "Windows/PostWindowsApi.h" +#include "Windows/HideWindowsPlatformTypes.h" +class FExportThread : public FRunnable +{ +public: + virtual void Stop() override; + virtual bool Init() override; + virtual uint32 Run() override; + virtual void Exit() override; + + bool bNeedClose = false; + std::atomic MaxPercent = 100.0f; + std::atomic CurrentPercent = 0.0f; + std::atomic Message = nullptr; + + std::atomic SubMaxPercent = 100.0f; + std::atomic SubCurrentPercent = 0.0f; + + HWND ProcessWindow = nullptr; + HWND ProcessBar = nullptr; + HWND ProcessText = nullptr; + HWND SubProcessText = nullptr; +}; diff --git a/Source/Cut5/Interface/VideoInterface.cpp b/Source/Cut5/Interface/VideoInterface.cpp index a88088f..58c8d22 100644 --- a/Source/Cut5/Interface/VideoInterface.cpp +++ b/Source/Cut5/Interface/VideoInterface.cpp @@ -107,6 +107,11 @@ uint32 FVideoThread::Run() uint8* RawData = nullptr; int32 Width = AllocatedFrame->width; + if (ClipData.ClipType == ETrackType::LightBarTrack) + { + RawData = new uint8[FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4]; + Width = FGlobalData::LightArrayX; + } if (ClipData.ClipType == ETrackType::LightArrayTrack) { RawData = new uint8[FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4]; @@ -172,6 +177,26 @@ uint32 FVideoThread::Run() sws_scale(SwsCtx, AllocatedFrame->data, AllocatedFrame->linesize, 0, AllocatedFrame->height, Dest, DestLineSize); sws_freeContext(SwsCtx); } + else if (ClipData.ClipType == ETrackType::LightBarTrack) + { + + + const AVCodecContext* VideoCodecContext = NewPropertyData.VideoCodecContext; + struct SwsContext* SwsCtx = sws_getContext( + AllocatedFrame->width, AllocatedFrame->height, VideoCodecContext->pix_fmt, + FGlobalData::LightArrayX, FGlobalData::LightArrayY, AV_PIX_FMT_BGRA, + SWS_BILINEAR, nullptr, nullptr, nullptr + ); + if (!SwsCtx) + { + UE_LOG(LogTemp, Error, TEXT("Error creating swsContext")); + CurrentSeekingFrame = -1; + continue;; + } + + sws_scale(SwsCtx, AllocatedFrame->data, AllocatedFrame->linesize, 0, AllocatedFrame->height, Dest, DestLineSize); + sws_freeContext(SwsCtx); + } int32 X = AllocatedFrame->width; @@ -190,6 +215,13 @@ uint32 FVideoThread::Run() FMemory::Memcpy(ColorArray.GetData(), RawData, FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4); MainInterface->OnUpdateLightArray(ColorArray); } + if (ClipData.ClipType == ETrackType::LightBarTrack) + { + TArray ColorArray; + ColorArray.Init(FColor::Black, FGlobalData::LightArrayX * FGlobalData::LightArrayY); + FMemory::Memcpy(ColorArray.GetData(), RawData, FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4); + MainInterface->OnUpdateLightBar(ColorArray); + } }); // }); diff --git a/Source/Cut5/Utils/CutPlatformUtils.cpp b/Source/Cut5/Utils/CutPlatformUtils.cpp index a7be6bd..44449be 100644 --- a/Source/Cut5/Utils/CutPlatformUtils.cpp +++ b/Source/Cut5/Utils/CutPlatformUtils.cpp @@ -4,19 +4,8 @@ HWND FCutPlatformUtils::CreateProcessWindow() { - HWND Process = ::FindWindowW(nullptr, *FApp::GetName()); - if (Process) - { - HWND ProcessBar = ::CreateWindowExW(0, PROGRESS_CLASS, NULL, - WS_CHILD | WS_VISIBLE, 0, 0, 200, 20, - Process, (HMENU) 0, NULL, NULL); - - ::SendMessageW(ProcessBar, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); - return ProcessBar; - } + return nullptr; - - } void FCutPlatformUtils::UpdateProcess(HWND hwnd, float Progress, FString Message) diff --git a/Source/Cut5/Utils/Utils.cpp b/Source/Cut5/Utils/Utils.cpp index ec2461d..df1cbd1 100644 --- a/Source/Cut5/Utils/Utils.cpp +++ b/Source/Cut5/Utils/Utils.cpp @@ -317,6 +317,33 @@ TArray FUtils::TrackEncodeVideo(const FTrackData& TrackData, c { TArray ClipData = TrackData.ClipData; ClipData.Sort([](const FClipData& A, const FClipData& B) {return A.ClipStartFrame < B.ClipStartFrame; }); + + + if (FGlobalData::Export_OnlyXML) + { + int32 i = 0; + TArray EncodeVideoInfos; + for (FClipData& TempClipData : ClipData) + { + if (!TempClipData.ResourcePropertyDataPtr) + continue; + if (TempClipData.ResourcePropertyDataPtr->Context) + { + FEncodeVideoInfo EncodeVideoInfo; + EncodeVideoInfo.EncodedVideoTimeCode = FGlobalData::GetTimeData(TempClipData.ClipStartFrame); + 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++; + } + return EncodeVideoInfos; + } int32 i = 0; TArray EncodeVideoInfos; @@ -333,8 +360,6 @@ TArray FUtils::TrackEncodeVideo(const FTrackData& TrackData, c int32 EndMilli = TempClipData.VideoEndFrame % static_cast(FGlobalData::GlobalFPS); FString NewStartMilli = FUtils::GetMsFromString(FGlobalData::GetTimeData(StartMilli)); FString NewEndMilli = FUtils::GetMsFromString(FGlobalData::GetTimeData(EndMilli)); - NewStartMilli = FString::Printf(TEXT("%04d"), FCString::Atoi(*NewStartMilli)); - NewEndMilli = FString::Printf(TEXT("%04d"), FCString::Atoi(*NewEndMilli)); FString StartTime = FString::Printf(TEXT("%02d:%02d:%02d.%s"), StartTimespan.GetHours(), StartTimespan.GetMinutes(), StartTimespan.GetSeconds(), *NewStartMilli); FString EndTime = FString::Printf(TEXT("%02d:%02d:%02d.%s"), EndTimespan.GetHours(), EndTimespan.GetMinutes(), EndTimespan.GetSeconds(), *NewEndMilli); @@ -398,6 +423,8 @@ FEncodeVideoInfo FUtils::TrackEncodeAudio(const FTrackData& TrackData, const FSt int32 i = 0; for (FClipData& TempClipData : ClipData) { + if (!TempClipData.ResourcePropertyDataPtr) + continue; if (TempClipData.ResourcePropertyDataPtr->Context) { SavedClipData = TempClipData; @@ -565,6 +592,29 @@ TArray FUtils::ExportPsaf(FTrackData TrackData, const FString& using namespace cv; TArray ClipData = TrackData.ClipData; ClipData.Sort([](const FClipData& A, const FClipData& B) {return A.ClipStartFrame < B.ClipStartFrame; }); + + if (FGlobalData::Export_OnlyXML) + { + TArray EncodeVideoInfos; + int32 i = 0; + for (FClipData& TempClipData : ClipData) + { + FString ExportName = FGuid::NewGuid().ToString();; + if (TempClipData.ResourcePropertyDataPtr) + { + FEncodeVideoInfo EncodeVideoInfo; + FString String = ExportPath + FString::FromInt(i) + ".psaf"; + EncodeVideoInfo.EncodedVideoName = FPaths::GetBaseFilename(String) + ".psaf"; + EncodeVideoInfo.EncodedVideoTimeCode = FGlobalData::GetTimeData(TempClipData.ClipStartFrame); + + EncodeVideoInfo.TrackData = TrackData; + EncodeVideoInfo.ClipData = TempClipData; + EncodeVideoInfos.Add(EncodeVideoInfo); + } + } + return EncodeVideoInfos; + } + TArray EncodeVideoInfos; int32 i = 0; for (FClipData& TempClipData : ClipData) @@ -625,9 +675,9 @@ TArray FUtils::ExportPsaf(FTrackData TrackData, const FString& Size old_size = frameSize; - capture.set(CAP_PROP_POS_FRAMES, TempClipData.ClipStartFrame); + capture.set(CAP_PROP_POS_FRAMES, TempClipData.VideoStartFrame); int32 frameCount = capture.get(CV_CAP_PROP_FRAME_COUNT); - frameCount -= ClipData[i].ClipStartFrame; + frameCount -= ClipData[i].VideoStartFrame; UE_LOG(LogTemp, Log, TEXT("frameCount: %s"), *FString::FromInt(frameCount)); char p[128] = "pasf"; @@ -695,17 +745,17 @@ TArray FUtils::ExportPsaf(FTrackData TrackData, const FString& int8 g = frame.at(row, col)[1]; int8 b = frame.at(row, col)[0]; - if (r == 1) + if (r == 1 || r == 2) { - r -= 1; + r = 0; } - if (g == 1) + if (g == 1 || g == 2) { - g -= 1; + g = 0; } - if (b == 1) + if (b == 1 || b == 2) { - b -= 1; + b = 0; } outfile.write(reinterpret_cast(&r), sizeof(uint8)); @@ -725,17 +775,17 @@ TArray FUtils::ExportPsaf(FTrackData TrackData, const FString& int8 g = frame.at(row, col)[1]; int8 b = frame.at(row, col)[0]; - if (r == 1) + if (r == 1 || r == 2) { - r -= 1; + r = 0; } - if (g == 1) + if (g == 1 || g == 2) { - g -= 1; + g = 0; } - if (b == 1) + if (b == 1 || b == 2) { - b -= 1; + b = 0; } outfile.write(reinterpret_cast(&r), sizeof(uint8)); @@ -758,17 +808,17 @@ TArray FUtils::ExportPsaf(FTrackData TrackData, const FString& int8 g = frame.at(row, col)[1]; int8 b = frame.at(row, col)[0]; - if (r == 1) + if (r == 1 || r == 2) { - r -= 1; + r = 0; } - if (g == 1) + if (g == 1 || g == 2) { - g -= 1; + g = 0; } - if (b == 1) + if (b == 1 || b == 2) { - b -= 1; + b = 0; } outfile.write(reinterpret_cast(&r), sizeof(uint8)); @@ -787,17 +837,17 @@ TArray FUtils::ExportPsaf(FTrackData TrackData, const FString& int8 g = frame.at(row, col)[1]; int8 b = frame.at(row, col)[0]; - if (r == 1) + if (r == 1 || r == 2) { - r -= 1; + r = 0; } - if (g == 1) + if (g == 1 || g == 2) { - g -= 1; + g = 0; } - if (b == 1) + if (b == 1 || b == 2) { - b -= 1; + b = 0; } outfile.write(reinterpret_cast(&r), sizeof(uint8)); @@ -818,17 +868,17 @@ TArray FUtils::ExportPsaf(FTrackData TrackData, const FString& int8 g = frame.at(row, col)[1]; int8 b = frame.at(row, col)[0]; - if (r == 1) + if (r == 1 || r == 2) { - r -= 1; + r = 0; } - if (g == 1) + if (g == 1 || g == 2) { - g -= 1; + g = 0; } - if (b == 1) + if (b == 1 || b == 2) { - b -= 1; + b = 0; } outfile.write(reinterpret_cast(&r), sizeof(uint8)); @@ -846,17 +896,17 @@ TArray FUtils::ExportPsaf(FTrackData TrackData, const FString& int8 g = frame.at(row, col)[1]; int8 b = frame.at(row, col)[0]; - if (r == 1) + if (r == 1 || r == 2) { - r -= 1; + r = 0; } - if (g == 1) + if (g == 1 || g == 2) { - g -= 1; + g = 0; } - if (b == 1) + if (b == 1 || b == 2) { - b -= 1; + b = 0; } outfile.write(reinterpret_cast(&r), sizeof(uint8)); @@ -960,9 +1010,9 @@ FString FUtils::GetMsNumberFromStringWithZFill(FString TimeString) FString FUtils::Color2Hex3(FColor Color) { - Color.R = FMath::GetMappedRangeValueClamped(FVector2D(0, 0xFF), FVector2D(0, 0x64), Color.R); - Color.G = FMath::GetMappedRangeValueClamped(FVector2D(0, 0xFF), FVector2D(0, 0x64), Color.G); - Color.B = FMath::GetMappedRangeValueClamped(FVector2D(0, 0xFF), FVector2D(0, 0x64), Color.B); + Color.R = FMath::GetMappedRangeValueClamped(FVector2D(0, 0xFF), FVector2D(0, 0x32), Color.R); + Color.G = FMath::GetMappedRangeValueClamped(FVector2D(0, 0xFF), FVector2D(0, 0x32), Color.G); + Color.B = FMath::GetMappedRangeValueClamped(FVector2D(0, 0xFF), FVector2D(0, 0x32), Color.B); return FString::Printf(TEXT("%02X%02X%02X"), Color.R, Color.G, Color.B); } diff --git a/Source/Cut5/Widgets/Commands/TimelineClipCommands.cpp b/Source/Cut5/Widgets/Commands/TimelineClipCommands.cpp index feadc63..1ba5d6c 100644 --- a/Source/Cut5/Widgets/Commands/TimelineClipCommands.cpp +++ b/Source/Cut5/Widgets/Commands/TimelineClipCommands.cpp @@ -8,6 +8,7 @@ void FTimelineClipCommands::RegisterCommands() UI_COMMAND(Fill2Start, "填充到开头", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(Fill2End, "填充到结尾", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(Cycle, "循环", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(FillPlayers, "填充至所有玩家轨道", "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()); diff --git a/Source/Cut5/Widgets/Commands/TimelineClipCommands.h b/Source/Cut5/Widgets/Commands/TimelineClipCommands.h index e235c00..fff4767 100644 --- a/Source/Cut5/Widgets/Commands/TimelineClipCommands.h +++ b/Source/Cut5/Widgets/Commands/TimelineClipCommands.h @@ -21,6 +21,7 @@ public: TSharedPtr Break; TSharedPtr Fill2Start; TSharedPtr Fill2End; + TSharedPtr FillPlayers; TSharedPtr CancelCycle; TSharedPtr Cycle; TSharedPtr AddCursorHere; diff --git a/Source/Cut5/Widgets/Curtain/SCurtain.cpp b/Source/Cut5/Widgets/Curtain/SCurtain.cpp index f7a5544..64fd0e9 100644 --- a/Source/Cut5/Widgets/Curtain/SCurtain.cpp +++ b/Source/Cut5/Widgets/Curtain/SCurtain.cpp @@ -91,6 +91,7 @@ void SCurtain::Construct(const FArguments& InArgs) if (!Curtain->bIsActive) { OpenThis(); + } }) .Text(FText::FromString(Curtain->CurtainName)) @@ -160,6 +161,7 @@ TSharedPtr SCurtain::OpenThis() CurtainPanel->CallRender(); + // 没有Curtain就Create一个 if (!FPaths::FileExists(FUtils::CurtainFullPath(Curtain->CurtainUUID.ToString()))) { @@ -182,7 +184,71 @@ TSharedPtr SCurtain::OpenThis() CurtainDragDrop->DragDropType = FCutDragDropBase::EType::CurtainDrag; CurtainDragDrop->DraggingWidget = SharedThis(this); + + CurtainPanel->MainWidgetInterface->UpdateProperties(nullptr); + CurtainPanel->MainWidgetInterface->UpdateProperties(this); + return CurtainDragDrop; } +FProperties* SCurtain::GetProperties() +{ + return IPropertiesInterface::GetProperties(); +} + +TSharedPtr SCurtain::GetPropertiesWidget() +{ + FTextBlockStyle NormalText = FAppStyle::GetWidgetStyle("NormalText"); + NormalText.SetFontSize(13); + + FCurtain& CurtainRef = *Curtain; + + PropertiesWidget = + SNew(SVerticalBox) + + SVerticalBox::Slot() + .SizeParam(FAuto()) + .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()) + .HAlign(HAlign_Right) + [ + SNew(SBox) + .WidthOverride(136) + .HeightOverride(32) + [ + SNew(SCheckBox) + .IsChecked_Lambda([this, &CurtainRef]() + { + return CurtainRef.IsGlobal ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; + }) + .OnCheckStateChanged_Lambda([this, &CurtainRef](const ECheckBoxState State) + { + CurtainRef.IsGlobal = State == ECheckBoxState::Checked; + }) + ] + ] + ] + ]; + return PropertiesWidget; +} + END_SLATE_FUNCTION_BUILD_OPTIMIZATION diff --git a/Source/Cut5/Widgets/Curtain/SCurtain.h b/Source/Cut5/Widgets/Curtain/SCurtain.h index b547643..5d4cfc4 100644 --- a/Source/Cut5/Widgets/Curtain/SCurtain.h +++ b/Source/Cut5/Widgets/Curtain/SCurtain.h @@ -3,13 +3,14 @@ #pragma once #include "CoreMinimal.h" +#include "Cut5/Interface/PropertiesInterface.h" #include "Cut5/Widgets/DefineGlobal.h" #include "Widgets/SCompoundWidget.h" /** * */ -class CUT5_API SCurtain : public SCompoundWidget +class CUT5_API SCurtain : public SCompoundWidget, public IPropertiesInterface { public: SLATE_BEGIN_ARGS(SCurtain) @@ -36,6 +37,9 @@ public: // FButtonStyle UnSelectedButtonStyle; FButtonStyle SelectedButtonStyle = FButtonStyle::GetDefault(); + + virtual FProperties* GetProperties() override; + virtual TSharedPtr GetPropertiesWidget() override; }; diff --git a/Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp b/Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp index 4d037b3..b04e1ee 100644 --- a/Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp +++ b/Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp @@ -294,6 +294,7 @@ void SCurtainPanel::UnSelectAllCurtain() void SCurtainPanel::CallRender() { + // MainWidgetInterface->UpdateProperties(nullptr); ScrollBox->ClearChildren(); GroupWidgets.Empty(); for (FCurtainGroup& Group : Groups) diff --git a/Source/Cut5/Widgets/DefineGlobal.h b/Source/Cut5/Widgets/DefineGlobal.h index 74fda7a..26b25e9 100644 --- a/Source/Cut5/Widgets/DefineGlobal.h +++ b/Source/Cut5/Widgets/DefineGlobal.h @@ -34,6 +34,8 @@ public: inline static FString Version = "3.0"; inline static FString CutVersion = "1.1"; inline static FString ExportPath = ""; + + inline static bool Export_OnlyXML = false; inline static TArray ExportErrorString; @@ -345,7 +347,7 @@ struct CUT5_API FClipData : public TSharedFromThis Ar << ClipData.bIsCycle; Ar << ClipData.AudioCurtains; Ar << ClipData.bIsVirtual; - Ar << ClipData.VirtualCurtainName; + Ar << ClipData.VirtualCurtainGuid; return Ar; }; @@ -455,7 +457,7 @@ struct CUT5_API FClipData : public TSharedFromThis TArray PlayerLightData; EPresetType PresetType = EPresetType::NotAPresets; bool bIsVirtual = false; - FString VirtualCurtainName = ""; + FGuid VirtualCurtainGuid = FGuid(); // Placeholder @@ -843,11 +845,13 @@ public: FTimelineInfo TimelineInfo; bool bIsActive = false; int32 Step = 0; + bool IsGlobal = true; friend FArchive& operator<< (FArchive& Ar, FCurtain& Curtain) { Ar << Curtain.CurtainName; Ar << Curtain.CurtainUUID; Ar << Curtain.TimelineInfo; + Ar << Curtain.IsGlobal; return Ar; } }; diff --git a/Source/Cut5/Widgets/DragDropOperator/DragDropOperator.cpp b/Source/Cut5/Widgets/DragDropOperator/DragDropOperator.cpp index d6ce57c..664b936 100644 --- a/Source/Cut5/Widgets/DragDropOperator/DragDropOperator.cpp +++ b/Source/Cut5/Widgets/DragDropOperator/DragDropOperator.cpp @@ -556,16 +556,11 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& FVector2D StartPos = ClipSelectDragDrop->ScrollResultStartPosition; FVector2D EndPos = ClipSelectDragDrop->ScrollResultEndPosition; - // GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("StartPos : %f, %f"), StartPos.X, StartPos.Y)); - // GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("EndPos : %f, %f"), EndPos.X, EndPos.Y)); - auto IsInRange = [this, StartPos, EndPos](FClipData& ClipData) { const float ClipStartTime = ClipData.ClipStartFrame * FGlobalData::DefaultTimeTickSpace; const float ClipEndTime = ClipData.ClipEndFrame * FGlobalData::DefaultTimeTickSpace; - // GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, FString::Printf(TEXT("ClipStartTime : %f"), ClipStartTime)); - // GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, FString::Printf(TEXT("ClipEndTime : %f"), ClipEndTime)); - + if (StartPos.X < ClipStartTime && EndPos.X > ClipStartTime) { return true; @@ -846,6 +841,7 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& { NewClipData.ClipType = ETrackType::AudioTrackR; NewClipData.ClipGuid = FGuid::NewGuid(); + NewClipData.BindTrackGuid = TrackData->DeviceTrack.Guid; TrackData->ClipData.Add(NewClipData); UpdateClipProcess(SavedMainInterface, NewClipData); } @@ -857,6 +853,7 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& { NewClipData.ClipType = ETrackType::AudioTrack; NewClipData.ClipGuid = FGuid::NewGuid(); + NewClipData.BindTrackGuid = TrackData->DeviceTrack.Guid; TrackData->ClipData.Add(NewClipData); UpdateClipProcess(SavedMainInterface, NewClipData); } diff --git a/Source/Cut5/Widgets/FX/SEffectCard.cpp b/Source/Cut5/Widgets/FX/SEffectCard.cpp index 57db788..90d79ae 100644 --- a/Source/Cut5/Widgets/FX/SEffectCard.cpp +++ b/Source/Cut5/Widgets/FX/SEffectCard.cpp @@ -395,6 +395,7 @@ TSharedPtr SEffectCard::GetPropertiesWidget() return false; } } + return true; }) .OnTextCommitted_Lambda([this](const FText& InText, ETextCommit::Type InCommitType) @@ -567,6 +568,46 @@ TSharedPtr SEffectCard::GetPropertiesWidget() ] ] ] + ] + + SVerticalBox::Slot() + .Padding(0, 16, 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(SButton) + .Text(FText::FromString(TEXT("恢复默认"))) + .OnClicked_Lambda([this]() + { + CardProperty->UsedCurtains.Empty(); + CardProperty->JumpStepCurtains = FStringWithGUID(); + return FReply::Handled(); + }) + ] + ] + ] ]; return PropertiesWidget; diff --git a/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp b/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp index 0149293..c6c4591 100644 --- a/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp +++ b/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp @@ -213,6 +213,9 @@ void SEffectCardGroup::Construct(const FArguments& InArgs) return false; } } + // ID不能重复 + + return true; }) .OnTextCommitted_Lambda([this](const FText& InText, ETextCommit::Type InCommitType) @@ -377,7 +380,48 @@ void SEffectCardGroup::Construct(const FArguments& InArgs) ] ] + ] + + SVerticalBox::Slot() + .Padding(0, 16, 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(SButton) + .Text(FText::FromString(TEXT("恢复默认"))) + .OnClicked_Lambda([this]() + { + EffectCardGroup->UsedCurtains.Empty(); + EffectCardGroup->JumpStepCurtains = FStringWithGUID(); + return FReply::Handled(); + }) + ] + ] + ] ]; + PropertiesInterfaceGUID = EffectCardGroup->Guid; CallRender(); } @@ -419,24 +463,8 @@ void SEffectCardGroup::CallRender() .OnClicked_Lambda([this]() { - - - - - int32 ID = 0; - for (int32 i = 0; i < EffectCardPanel->EffectCardGroups.Num(); i++) - { - if (EffectCardPanel->EffectCardGroups[i].bIsDedicated) - { - for (int32 j = 0; j < EffectCardPanel->EffectCardGroups[i].Cards.Num(); j++) - { - ID++; - } - } - ID++; - } - // 新建卡牌后 对卡牌进行个体保存。 + int32 ID = EffectCardPanel->GetCurrentID(true); FEffectCardProperty NewCard; NewCard.Name = TEXT("未命名") + FString::FromInt(ID); NewCard.ID = ID; diff --git a/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp b/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp index 968394a..87dce3d 100644 --- a/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp +++ b/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp @@ -107,15 +107,7 @@ void SEffectCardsPanel::CallRender() const FGuid NewGuid = FGuid::NewGuid(); FEffectCardGroup* Group = AddNewGroup(TEXT("新建组") + NewGuid.ToString()); Group->Guid = NewGuid; - int32 ID = 0; - for (int32 i = 0; i < EffectCardGroups.Num(); i++) - { - for (int32 j = 0; j < EffectCardGroups[i].Cards.Num(); j++) - { - ID++; - } - ID++; - } + int32 ID = GetCurrentID(true); Group->ID = ID; const FString NewPath = FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, TEXT("FX"), NewGuid.ToString() + TEXT(".bin")); @@ -256,10 +248,10 @@ void SEffectCardsPanel::DuplicateCard(const FGuid& Guid, const FGuid& ToGroupGui { if (EffectCardGroups[k].Guid == ToGroupGuid) { - if (EffectCardGroups[k].Cards.Contains(NewEffectCardProperty)) - { - return; - } + // if (EffectCardGroups[k].Cards.Contains(NewEffectCardProperty)) + // { + // return; + // } EffectCardGroups[k].Cards.Add(NewEffectCardProperty); break; } @@ -399,4 +391,53 @@ void SEffectCardsPanel::LoadPanel(const FString& Path) CallRender(); } +bool SEffectCardsPanel::IsIdExists(int32 ID) +{ + for (FEffectCardGroup& Group : EffectCardGroups) + { + if (Group.ID == ID) + { + return true; + } + for (const FEffectCardProperty& Property : Group.Cards) + { + if (Property.ID == ID) + { + return true; + } + } + } + return false; +} + +int32 SEffectCardsPanel::GetCurrentID(bool Iterate) +{ + if (FPaths::FileExists(FGlobalData::BasePath / FGlobalData::CurrentProjectName / "ID.bin")) + { + FString IDData; + FFileHelper::LoadFileToString(IDData, *(FGlobalData::BasePath / FGlobalData::CurrentProjectName / "ID.bin")); + + if (Iterate) + { + int32 ID = FCString::Atoi(*IDData); + ID++; + const FString NewIDData = FString::FromInt(ID); + FFileHelper::SaveStringToFile(NewIDData, *(FGlobalData::BasePath / FGlobalData::CurrentProjectName / "ID.bin")); + return ID; + } + + return FCString::Atoi(*IDData); + } + else + { + const FString IDData = "1"; + FFileHelper::SaveStringToFile(IDData, *(FGlobalData::BasePath / FGlobalData::CurrentProjectName / "ID.bin")); + + return 1; + } + + return -1; + +} + END_SLATE_FUNCTION_BUILD_OPTIMIZATION diff --git a/Source/Cut5/Widgets/FX/SEffectCardsPanel.h b/Source/Cut5/Widgets/FX/SEffectCardsPanel.h index 07aa9c3..d367e99 100644 --- a/Source/Cut5/Widgets/FX/SEffectCardsPanel.h +++ b/Source/Cut5/Widgets/FX/SEffectCardsPanel.h @@ -97,5 +97,9 @@ public: void SavePanel(const FString& Path); void LoadPanel(const FString& Path); + + bool IsIdExists(int32 ID); + + int32 GetCurrentID(bool Iterate = true); }; diff --git a/Source/Cut5/Widgets/MicroWidgets/SColorPanel.cpp b/Source/Cut5/Widgets/MicroWidgets/SColorPanel.cpp index 8723363..adf5294 100644 --- a/Source/Cut5/Widgets/MicroWidgets/SColorPanel.cpp +++ b/Source/Cut5/Widgets/MicroWidgets/SColorPanel.cpp @@ -15,6 +15,7 @@ BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION void SColorPanel::Construct(const FArguments& InArgs) { + OnColorCommit = InArgs._OnColorCommit; ColorPtr = InArgs._ColorPtr; CurrentSelectColor = ColorPtr->LinearRGBToHSV(); ColorS = ColorPtr->LinearRGBToHSV().G; @@ -149,6 +150,7 @@ void SColorPanel::Construct(const FArguments& InArgs) .Image(FUtils::GetBrushFromImage(FUtils::GetResourcesPath("ColorPanelClose.png"), {})) .OnMouseButtonDown_Lambda([this](const FGeometry&, const FPointerEvent&) { + OnColorCommit.ExecuteIfBound(CurrentSelectColor); GEngine->GameViewport->RemoveViewportWidgetContent(SharedThis(this)); return FReply::Handled(); }) diff --git a/Source/Cut5/Widgets/MicroWidgets/SColorPanel.h b/Source/Cut5/Widgets/MicroWidgets/SColorPanel.h index 48fed8f..d6d4d07 100644 --- a/Source/Cut5/Widgets/MicroWidgets/SColorPanel.h +++ b/Source/Cut5/Widgets/MicroWidgets/SColorPanel.h @@ -11,10 +11,12 @@ class CUT5_API SColorPanel : public SCompoundWidget { public: + DECLARE_DELEGATE_OneParam(FOnColorCommit, FLinearColor) SLATE_BEGIN_ARGS(SColorPanel) { } SLATE_ARGUMENT(FLinearColor*, ColorPtr) + SLATE_EVENT(FOnColorCommit, OnColorCommit) SLATE_END_ARGS() /** Constructs this widget with InArgs */ @@ -29,6 +31,7 @@ public: TSharedPtr SBar; TSharedPtr ColorBox; TSharedPtr ColorImage; + FOnColorCommit OnColorCommit; FLinearColor CurrentSelectColor = FLinearColor(1, 1, 0, 1); float ColorS = 0; diff --git a/Source/Cut5/Widgets/SCustomInputPanel.cpp b/Source/Cut5/Widgets/SCustomInputPanel.cpp index 3457c5d..5fb3158 100644 --- a/Source/Cut5/Widgets/SCustomInputPanel.cpp +++ b/Source/Cut5/Widgets/SCustomInputPanel.cpp @@ -310,16 +310,12 @@ void SCustomInputPanel::Construct(const FArguments& InArgs) .Justification(ETextJustify::Center) ] ] - ] ] ] ] - ] - ] - ]; @@ -337,7 +333,7 @@ void SCustomInputPanel::Construct(const FArguments& InArgs) AddPreset(TEXT("橘色"), TEXT("橘色.dat"), EPresetType::Custom); AddPreset(TEXT("青柠"), TEXT("青柠.dat"), EPresetType::Custom); AddPreset(TEXT("音量\n玩家谈话"), TEXT("10"), EPresetType::Volume); - AddPreset(TEXT("音量\n视频底音"), TEXT("35"), EPresetType::Volume); + AddPreset(TEXT("音量\n视频底音"), TEXT("25"), EPresetType::Volume); AddPreset(TEXT("音量\n静音"), TEXT("0"), EPresetType::Volume); AddPreset(TEXT("启动投影"), TEXT(""), EPresetType::EnableProjector); AddPreset(TEXT("屏蔽投影"), TEXT(""), EPresetType::DisableProjector); diff --git a/Source/Cut5/Widgets/SCutMainWindow.cpp b/Source/Cut5/Widgets/SCutMainWindow.cpp index bd1edf4..3a9f6ab 100644 --- a/Source/Cut5/Widgets/SCutMainWindow.cpp +++ b/Source/Cut5/Widgets/SCutMainWindow.cpp @@ -18,6 +18,7 @@ #include "Commands/MainMenuCommands.h" #include "Commands/ShortcunCommands.h" #include "CustomPanel/SCustomPanel.h" +#include "Cut5/Interface/ExportThread.h" #include "Cut5/Utils/CutPlatformUtils.h" #include "Cut5/Utils/FFMPEGUtils.h" #include "Cut5/Utils/Utils.h" @@ -39,6 +40,8 @@ #include "Windows/AllowWindowsPlatformTypes.h" #include "Windows/WindowsPlatformApplicationMisc.h" #include "GenericPlatform/GenericPlatformApplicationMisc.h" +#include "SaveConverter/Timeline/TimelineLoader.h" +#include "SchUtils.h" BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION @@ -129,20 +132,9 @@ void SCutMainWindow::Construct(const FArguments& InArgs) .Justification(ETextJustify::Center) .OnDoubleClicked_Lambda([this](const FGeometry&, const FPointerEvent&) { - for (int32 i = CutTimeline->DeviceTrackGroups.Num() - 1; i >= 0; i--) - { - if (CutTimeline->DeviceTrackGroups[i].GroupType == ETrackType::AtomSphereLightTrack) - { - CutTimeline->DeviceTrackGroups.RemoveAt(i); - } - // for (int32 j = CutTimeline->DeviceTrackGroups[i].DeviceTracks.Num() - 1; j >= 0; j--) - // { - // if (CutTimeline->DeviceTrackGroups[i].DeviceTracks[j].DeviceType == ETrackType::AtomSphereLightTrack) - // { - // CutTimeline->DeviceTrackGroups[i].DeviceTracks.RemoveAt(j); - // } - // } - } + FRunnable* Runnable = new FExportThread(); + FRunnableThread* RunnableThread = FRunnableThread::Create(Runnable, TEXT("ExportThread")); + return FReply::Handled(); }) ] @@ -726,6 +718,10 @@ void SCutMainWindow::Tick(const FGeometry& AllottedGeometry, const double InCurr TotalTime = 0; } TotalTime += InDeltaTime; + + + SCH_DEBUG_INT32(114514, "TestVar"); + // GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FString::Printf(TEXT("TestVar: %d"), SCH_DEBUG_INT32(114514, "TestVar"))); } int32 SCutMainWindow::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, @@ -858,6 +854,12 @@ void SCutMainWindow::OnUpdateSpotLight(int32 Index, FColor LightColor) } +void SCutMainWindow::OnUpdateLightBar(const TArray& LightArray) +{ + ICutMainWidgetInterface::OnUpdateLightBar(LightArray); + StatePanel->LightArray->LightBarColors = LightArray; +} + void SCutMainWindow::OnAddNewTrack(ETrackType Type) { ICutMainWidgetInterface::OnAddNewTrack(Type); @@ -978,12 +980,20 @@ bool SCutMainWindow::OpenProject(const FString& Project) FUtils::AddTips(SNew(STips).Title(TEXT("打开失败")).SubTitle(FString::Printf(TEXT("版本不匹配,无法打开项目,载入版本:%s, 当前版本:%s"), *LoadVersion, *FGlobalData::Version)).OnEnsure_Lambda([](const FString& String){})); return false; } + + + FExportThread* Thread = new FExportThread(); + FRunnableThread* RunnableThread = FRunnableThread::Create(Thread, TEXT("ImportThread")); // 记录所有导入资产链接 int32 PropertyDataNum = 0; Reader << PropertyDataNum; + + Thread->MaxPercent = PropertyDataNum; + Thread->CurrentPercent = 0; for (int32 i = 0; i < PropertyDataNum; i++) { + Thread->CurrentPercent = Thread->CurrentPercent + 1; FTimelinePropertyData TimelinePropertyData; Reader << TimelinePropertyData; @@ -1058,7 +1068,7 @@ bool SCutMainWindow::OpenProject(const FString& Project) } - + Thread->Stop(); return true; } @@ -1068,9 +1078,14 @@ void SCutMainWindow::ExportProject(const FString& ExportPath) if (ExportPath.IsEmpty()) return; - - HWND hwnd = FCutPlatformUtils::CreateProcessWindow(); - FCutPlatformUtils::UpdateProcess(hwnd, 50, TEXT("")); + ExportCards.Empty(); + TotalExported = 0; + int32 ExportCount = CalculateExportCount(); + Runnable = new FExportThread(); + FRunnableThread* RunnableThread = FRunnableThread::Create(Runnable, TEXT("ExportThread")); + Runnable->MaxPercent = ExportCount; + Runnable->CurrentPercent = TotalExported; + FGlobalData::ExportPath = ExportPath / FGlobalData::CurrentProjectName + TEXT("_XML"); @@ -1208,16 +1223,17 @@ void SCutMainWindow::ExportProject(const FString& ExportPath) { 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].Cards[j].ID))); + FExportCard ExportCard; 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))); - + ExportCard.CardName = EffectCardsPanel->EffectCardGroups[i].Cards[j].Name; + ExportCard.CardID = EffectCardsPanel->EffectCardGroups[i].Cards[j].ID; + ExportCard.CardType = TypeID; + ExportCard.Times = -1; + int32 ToStepID = 0; if (TypeID == 1) { @@ -1233,29 +1249,28 @@ void SCutMainWindow::ExportProject(const FString& ExportPath) } } } + ExportCard.Step = ToStepID; + ExportCard.SerialID.Add(EffectCardsPanel->EffectCardGroups[i].Cards[j].ID); - 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 - 1))); - Card->InsertNewChildElement("SerialNumberList")->InsertNewChildElement("SerialNumber")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(EffectCardsPanel->EffectCardGroups[i].Cards[j].ID))); + + ExportCard.TimelinePath = FUtils::SingleCardFullPath(EffectCardsPanel->EffectCardGroups[i].Cards[j].Guid.ToString()); + ExportCard.CardGuid = EffectCardsPanel->EffectCardGroups[i].Cards[j].Guid; + ExportCards.Add(ExportCard); + UE_LOG(LogTemp, Log, TEXT("ExportCard.TimelinePath = %s"), *ExportCard.TimelinePath); } } else { - tinyxml2::XMLElement* Card = CardList->InsertNewChildElement("Card"); - - - Card->InsertNewChildElement("ID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(EffectCardsPanel->EffectCardGroups[i].ID))); - + FExportCard ExportCard; + ExportCard.CardName = EffectCardsPanel->EffectCardGroups[i].GroupName; + ExportCard.CardID = EffectCardsPanel->EffectCardGroups[i].ID; 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))); - - + ExportCard.CardType = TypeID; + ExportCard.Times = -1; int32 ToStepID = 0; if (TypeID == 3) { @@ -1271,16 +1286,48 @@ void SCutMainWindow::ExportProject(const FString& ExportPath) } } } - 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"); + ExportCard.Step = ToStepID; for (int32 k = 0; k < EffectCardsPanel->EffectCardGroups[i].Cards.Num(); k++) { - SerialNumberList->InsertNewChildElement("SerialNumber")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(EffectCardsPanel->EffectCardGroups[i].Cards[k].ID))); + ExportCard.SerialID.Add(EffectCardsPanel->EffectCardGroups[i].Cards[k].ID); } + + + ExportCard.TimelinePath = FUtils::GroupFullPath(EffectCardsPanel->EffectCardGroups[i].Guid.ToString()); + ExportCard.CardGuid = EffectCardsPanel->EffectCardGroups[i].Guid; + ExportCards.Add(ExportCard); } - } + + Sort(ExportCards.GetData(), ExportCards.Num(), [](const FExportCard& A, const FExportCard& B) { return A.CardID < B.CardID; }); + int32 Count = 0; + for (int32 i = 0; i < ExportCards.Num(); i++) + { + if (ExportCards[i].CardType == 0 || ExportCards[i].CardType == 2) + { + ExportCards[i].SpecialEffectID = Count; + } + else + { + ExportCards[i].SpecialEffectID = -1; + } + Count++; + } + for (int32 i = 0; i < ExportCards.Num(); i++) + { + tinyxml2::XMLElement* Card = CardList->InsertNewChildElement("Card"); + Card->InsertNewChildElement("ID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(ExportCards[i].CardID))); + Card->InsertNewChildElement("Type")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(ExportCards[i].CardType))); + Card->InsertNewChildElement("Times")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(ExportCards[i].Times))); + Card->InsertNewChildElement("Step")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(ExportCards[i].Step))); + Card->InsertNewChildElement("SpecialEffectID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(ExportCards[i].SpecialEffectID))); + tinyxml2::XMLElement* SerialNumberList = Card->InsertNewChildElement("SerialNumberList"); + for (int32 k = 0; k < ExportCards[i].SerialID.Num(); k++) + { + SerialNumberList->InsertNewChildElement("SerialNumber")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(ExportCards[i].SerialID[k]))); + } + } + // KeyBoard tinyxml2::XMLElement* Keyboard = DeviceList->InsertNewChildElement("KeyBoard"); @@ -1323,6 +1370,8 @@ void SCutMainWindow::ExportProject(const FString& ExportPath) } FFileHelper::SaveStringToFile(Ended, *FUtils::GetProjectTempPath()); + + Runnable->Stop(); } @@ -1652,6 +1701,8 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par Event1->InsertNewChildElement("TimeCode")->InsertNewText("0"); } } + + int32 Count = 0; @@ -1670,6 +1721,9 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par } Count++; + + TotalExported++; + Runnable->CurrentPercent = Runnable->CurrentPercent + 1; } if (Count == 0) { @@ -1791,6 +1845,8 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par } } + TotalExported++; + Runnable->CurrentPercent = Runnable->CurrentPercent + 1; j++; } } @@ -1834,17 +1890,8 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par } } } - FString Filename; - for (FCurtainGroup& CurtainGroup : CurtainPanel->Groups) - { - for (const FCurtain& Curtain : CurtainGroup.Curtains) - { - if (Curtain.bIsActive) - { - Filename = Curtain.CurtainName + (CurrentTrackHead->TrackData.TrackType == ETrackType::LightArrayTrack ? TEXT("光阵") : TEXT("光条")); - } - } - } + FString Filename = GetCurrentSelectFileName() + (CurrentTrackHead->TrackData.TrackType == ETrackType::LightArrayTrack ? TEXT("光阵") : TEXT("光条")); + TArray EncodeVideoInfos = FUtils::ExportPsaf(StaticCastSharedPtr(CurrentTrackHead)->TrackData, *(FGlobalData::ExportPath / "PSAF" / Filename)); for (int32 j = 0; j < EncodeVideoInfos.Num(); j++) { @@ -2133,7 +2180,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundElement(tinyxml2::XMLElement* Pare tinyxml2::XMLElement* VolumeEventValue = VolumeEvent->InsertNewChildElement("Value"); VolumeEventTimeCode->InsertNewText("0"); - VolumeEventValue->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(ClipData.CurrentVolume))); + VolumeEventValue->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(100))); } } @@ -2265,11 +2312,14 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundListElement(tinyxml2::XMLElement* if (ClipData.bIsVirtual) { bIsVirtual = true; - const FString VirtualFileName = FGlobalData::ExportPath / "Sound" / ClipData.VirtualCurtainName; + FString GetSelectionName = GetSelectNameByGuid(ClipData.VirtualCurtainGuid); + const FString VirtualFileName = FGlobalData::ExportPath / "Sound" / GetSelectionName; FEncodeVideoInfo EncodeVideoInfo; EncodeVideoInfo.EncodedVideoName = VirtualFileName; EncodeVideoInfo.ClipData = ClipData; GetSoundElement(AudioList, EncodeVideoInfo); + TotalExported++; + Runnable->CurrentPercent = Runnable->CurrentPercent + 1; } } if (!bIsVirtual) @@ -2279,11 +2329,14 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundListElement(tinyxml2::XMLElement* if (ClipData.bIsVirtual) { bIsVirtual = true; - const FString VirtualFileName = FGlobalData::ExportPath / "Sound" / ClipData.VirtualCurtainName; + FString GetSelectionName = GetSelectNameByGuid(ClipData.VirtualCurtainGuid); + const FString VirtualFileName = FGlobalData::ExportPath / "Sound" / GetSelectionName; FEncodeVideoInfo EncodeVideoInfo; EncodeVideoInfo.EncodedVideoName = VirtualFileName; EncodeVideoInfo.ClipData = ClipData; GetSoundElement(AudioList, EncodeVideoInfo); + TotalExported++; + Runnable->CurrentPercent = Runnable->CurrentPercent + 1; } } } @@ -2298,6 +2351,9 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundListElement(tinyxml2::XMLElement* const FEncodeVideoInfo LeftEncodeVideoInfos = FUtils::TrackEncodeAudio(LeftTrackData, LeftNewExportFilePath); const FEncodeVideoInfo RightEncodeVideoInfos = FUtils::TrackEncodeAudio(RightTrackData, RightNewExportFilePath); + TotalExported++; + Runnable->CurrentPercent = Runnable->CurrentPercent + 1; + const FString ExportFilename = FGlobalData::ExportPath / "Sound" / GetCurrentSelectFileName(); const FEncodeVideoInfo End = FUtils::CombineAudio(LeftEncodeVideoInfos, RightEncodeVideoInfos, ExportFilename); @@ -2343,6 +2399,9 @@ tinyxml2::XMLElement* SCutMainWindow::GetProcessB(tinyxml2::XMLElement* Parent, { AutoNext = 1; AutoNextTimeLength = FUtils::GetMsFromString(FGlobalData::GetTimeData(AutoNextClipData[0].ClipStartFrame)); + + TotalExported++; + Runnable->CurrentPercent = Runnable->CurrentPercent + 1; } ProcessB->InsertNewChildElement("AutoNext")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(AutoNext))); @@ -2361,7 +2420,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetProcessB(tinyxml2::XMLElement* Parent, } tinyxml2::XMLElement* IsGlobal = ProcessB->InsertNewChildElement("IsGlobal"); { - IsGlobal->InsertNewText("1"); + IsGlobal->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(Curtain->IsGlobal))); } tinyxml2::XMLElement* State = ProcessB->InsertNewChildElement("State"); { @@ -2410,31 +2469,49 @@ tinyxml2::XMLElement* SCutMainWindow::GetSpecialEffectList(tinyxml2::XMLElement* { tinyxml2::XMLElement* SpecialEffectsList = Parent->InsertNewChildElement("SpecialEffectsList"); int32 SpecialEffectID = 0; - for (int32 i = 0; i < EffectCardsPanel->EffectCardGroups.Num(); i++) + for (FExportCard& ExportCard : ExportCards) { - if (!EffectCardsPanel->EffectCardGroups[i].bIsDedicated) - { - DeselectAll(); - EffectCardsPanel->EffectCardGroups[i].bIsActive = true; - OpenTimeline(FUtils::GroupFullPath(EffectCardsPanel->EffectCardGroups[i].Guid.ToString()), true, true); - CurrentSelectedPropertiesInterfaceGuid = EffectCardsPanel->EffectCardGroups[i].Guid; - GetSpecialEffectGroup(SpecialEffectsList, &EffectCardsPanel->EffectCardGroups[i]); - SpecialEffectID++; - continue; - } - for (int32 j = 0; j < EffectCardsPanel->EffectCardGroups[i].Cards.Num(); j++) - { - DeselectAll(); - EffectCardsPanel->EffectCardGroups[i].Cards[j].bIsActive = true; - OpenTimeline(FUtils::SingleCardFullPath(EffectCardsPanel->EffectCardGroups[i].Cards[j].Guid.ToString()), true, true); - CurrentSelectedPropertiesInterfaceGuid = EffectCardsPanel->EffectCardGroups[i].Cards[j].Guid; - GetSpecialEffect(SpecialEffectsList, &EffectCardsPanel->EffectCardGroups[i].Cards[j]); - SpecialEffectID++; - } - - SpecialEffectID++; - } + DeselectAll(); + SetActive(ExportCard.CardGuid); + OpenTimeline(ExportCard.TimelinePath, true, true); + tinyxml2::XMLElement* SpecialEffect = SpecialEffectsList->InsertNewChildElement("SpecialEffect"); + tinyxml2::XMLElement* Effect = SpecialEffect->InsertNewChildElement("Effect"); + Effect->SetAttribute("Name", TCHAR_TO_UTF8(*ExportCard.CardName)); + + tinyxml2::XMLElement* ID = Effect->InsertNewChildElement("ID"); + { + ID->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(ExportCard.SpecialEffectID))); + } + + FString AutoNextTimeLength = "-1"; + int32 AutoNext = 0; + TArray AutoNextClipData = CutTimeline->GetClipDataByType(ETrackType::AutoNext); + if (AutoNextClipData.Num() > 0) + { + AutoNext = 1; + AutoNextTimeLength = FUtils::GetMsFromString(FGlobalData::GetTimeData(AutoNextClipData[0].ClipStartFrame)); + } + + Effect->InsertNewChildElement("AutoNext")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(AutoNext))); + Effect->InsertNewChildElement("TimeLength")->InsertNewText(TCHAR_TO_UTF8(*AutoNextTimeLength)); + GetSoundListElement(Effect); + GetDeviceElement(Effect); + GetVideoListElement(Effect); + tinyxml2::XMLElement* IsGlobal = Effect->InsertNewChildElement("IsGlobal"); + { + int32 bIsGlobal = 0; + IsGlobal->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(bIsGlobal))); + } + tinyxml2::XMLElement* State = Effect->InsertNewChildElement("State"); + { + State->InsertNewText("0"); + } + + GetTrigger(SpecialEffect); + } + + if (SpecialEffectID == 0) { SpecialEffectsList->InsertNewText(""); @@ -2677,6 +2754,70 @@ tinyxml2::XMLElement* SCutMainWindow::GetGradientLight(tinyxml2::XMLElement* Par return nullptr; } +FTimelineInfo SCutMainWindow::GetSelectTimelineInfoByGuid(const FGuid& Guid) const +{ + for (FCurtainGroup& CurtainGroup : CurtainPanel->Groups) + { + for (const FCurtain& Curtain : CurtainGroup.Curtains) + { + if (Curtain.CurtainUUID == Guid) + { + return Curtain.TimelineInfo; + } + } + } + for (FEffectCardGroup& Group : EffectCardsPanel->EffectCardGroups) + { + if (!Group.bIsDedicated) + { + if (Group.Guid == Guid) + { + return Group.TimelineInfo; + } + } + for (FEffectCardProperty& Property : Group.Cards) + { + if (Property.Guid == Guid) + { + return Property.TimelineInfo; + } + } + } + return FTimelineInfo(); +} + +FString SCutMainWindow::GetSelectNameByGuid(const FGuid& Guid) const +{ + for (FCurtainGroup& CurtainGroup : CurtainPanel->Groups) + { + for (const FCurtain& Curtain : CurtainGroup.Curtains) + { + if (Curtain.CurtainUUID == Guid) + { + return TEXT("幕_") + Curtain.CurtainName; + } + } + } + for (FEffectCardGroup& Group : EffectCardsPanel->EffectCardGroups) + { + if (!Group.bIsDedicated) + { + if (Group.Guid == Guid) + { + return TEXT("特效组_") + Group.GroupName; + } + } + for (FEffectCardProperty& Property : Group.Cards) + { + if (Property.Guid == Guid) + { + return TEXT("特效卡_") + Property.Name; + } + } + } + return ""; +} + FGuid SCutMainWindow::GetCurrentSelectCurtain() const { for (FCurtainGroup& CurtainGroup : CurtainPanel->Groups) @@ -2689,9 +2830,57 @@ FGuid SCutMainWindow::GetCurrentSelectCurtain() const } } } + for (FEffectCardGroup& Group : EffectCardsPanel->EffectCardGroups) + { + if (!Group.bIsDedicated) + { + if (Group.bIsActive == true) + { + return Group.Guid; + } + } + for (FEffectCardProperty& Property : Group.Cards) + { + if (Property.bIsActive) + { + return Property.Guid; + } + } + } return FGuid(); } +void SCutMainWindow::SetActive(FGuid& Guid) const +{ + for (FCurtainGroup& CurtainGroup : CurtainPanel->Groups) + { + for (FCurtain& Curtain : CurtainGroup.Curtains) + { + if (Curtain.CurtainUUID == Guid) + { + Curtain.bIsActive = true; + } + } + } + for (FEffectCardGroup& Group : EffectCardsPanel->EffectCardGroups) + { + if (!Group.bIsDedicated) + { + if (Group.Guid == Guid) + { + Group.bIsActive = true; + } + } + for (FEffectCardProperty& Property : Group.Cards) + { + if (Property.Guid == Guid) + { + Property.bIsActive = true; + } + } + } +} + FTimelineInfo SCutMainWindow::GetCurrentSelectCurtainTimelineInfo() const { for (FCurtainGroup& CurtainGroup : CurtainPanel->Groups) @@ -2704,6 +2893,23 @@ FTimelineInfo SCutMainWindow::GetCurrentSelectCurtainTimelineInfo() const } } } + for (FEffectCardGroup& Group : EffectCardsPanel->EffectCardGroups) + { + if (!Group.bIsDedicated) + { + if (Group.bIsActive) + { + return Group.TimelineInfo; + } + } + for (FEffectCardProperty& Property : Group.Cards) + { + if (Property.bIsActive) + { + return Property.TimelineInfo; + } + } + } return FTimelineInfo(); } @@ -2733,6 +2939,7 @@ void SCutMainWindow::DeselectAll() } for (int32 i = 0; i < EffectCardsPanel->EffectCardGroups.Num(); ++i) { + EffectCardsPanel->EffectCardGroups[i].bIsActive = false; for (int32 j = 0; j < EffectCardsPanel->EffectCardGroups[i].Cards.Num(); ++j) { if (EffectCardsPanel->EffectCardGroups[i].Cards[j].bIsActive) @@ -2746,6 +2953,37 @@ void SCutMainWindow::DeselectAll() EffectCardsPanel->CallRender(); } +int32 SCutMainWindow::CalculateExportCount() +{ + int32 Count = 0; + for (FCurtainGroup& CurtainGroup : CurtainPanel->Groups) + { + for (FCurtain& Curtain : CurtainGroup.Curtains) + { + FTimelineLoader TimelineLoader(Curtain.TimelineInfo.CurrentOpenFullPath); + Count += TimelineLoader.GetClipData().Num(); + } + } + for (FEffectCardGroup& Group : EffectCardsPanel->EffectCardGroups) + { + if (!Group.bIsDedicated) + { + for (FEffectCardProperty& Property : Group.Cards) + { + FTimelineLoader TimelineLoader(Property.TimelineInfo.CurrentOpenFullPath); + Count += TimelineLoader.GetClipData().Num(); + } + } + for (FEffectCardProperty& Property : Group.Cards) + { + FTimelineLoader TimelineLoader(Property.TimelineInfo.CurrentOpenFullPath); + Count += TimelineLoader.GetClipData().Num(); + } + } + return Count; + +} + int32 SCutMainWindow::GetTrackID(FGuid Guid) const { const int32* Index = IDList.Find(Guid); diff --git a/Source/Cut5/Widgets/SCutMainWindow.h b/Source/Cut5/Widgets/SCutMainWindow.h index 2cd1214..dff3b57 100644 --- a/Source/Cut5/Widgets/SCutMainWindow.h +++ b/Source/Cut5/Widgets/SCutMainWindow.h @@ -13,6 +13,7 @@ #include "CustomPanel/SCustomPanel.h" #include "StatePanel/SVideoPlayer.h" #include "Cut5/Interface/CutMainWidgetInterface.h" +#include "Cut5/Interface/ExportThread.h" #include "Cut5/Interface/SoundInterface.h" #include "FX/SEffectCardsPanel.h" #include "StatePanel/SStatePanel.h" @@ -21,6 +22,23 @@ /** * */ + +struct FExportCard +{ + + FString CardName; + int32 CardID; + int32 CardType; + int32 SpecialEffectID; + int32 Times; + int32 Step; + TArray SerialID; + + FString TimelinePath; + FGuid CardGuid; + +}; + class CUT5_API SCutMainWindow : public SCompoundWidget, public ICutMainWidgetInterface { public: @@ -54,7 +72,7 @@ public: - + TArray ExportCards; void CloseAllThreads(); FSoundThread* SoundThread; @@ -69,6 +87,7 @@ public: virtual void OnUpdatePlayers(TSharedPtr TrackBody, FColor PlayerColor) override; virtual void OnUpdateProjector(int32 Index, bool bEnableProjector) override; virtual void OnUpdateSpotLight(int32 Index, FColor LightColor) override; + virtual void OnUpdateLightBar(const TArray& LightArray) override; virtual void OnAddNewTrack(ETrackType Type) override; virtual void OnRemoveTrack(FGuid Guid) override; virtual void OnUpdateSound(uint8* Data, int32 Size) override; @@ -97,6 +116,8 @@ public: virtual ESelectMode GetSelectedMode() override; virtual SCutMainWindow* GetSelf() override; + FExportThread* Runnable; + FPointerEvent NewMouseEvent; virtual bool SupportsKeyboardFocus() const override { return true; }; virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override; @@ -125,12 +146,17 @@ public: tinyxml2::XMLElement* GetFlashLight(tinyxml2::XMLElement* Parent, const FClipData& ClipData); tinyxml2::XMLElement* GetGradientLight(tinyxml2::XMLElement* Parent, const FClipData& ClipData); FString GetCurrentSelectFileName() const; - - + FTimelineInfo GetSelectTimelineInfoByGuid(const FGuid& Guid) const; + FString GetSelectNameByGuid(const FGuid& Guid) const; FGuid GetCurrentSelectCurtain() const; + void SetActive(FGuid& Guid) const; FTimelineInfo GetCurrentSelectCurtainTimelineInfo() const; bool IsSelectCurtain() const; void DeselectAll(); + + int32 TotalExported = 0; + + int32 CalculateExportCount(); int32 RotatorSpeakerIndex = 0; int32 LightArrayIndex = 0; @@ -152,17 +178,24 @@ inline FString SCutMainWindow::GetCurrentSelectFileName() const { if (Curtain.bIsActive) { - return Curtain.CurtainName; + return TEXT("幕_") + Curtain.CurtainName; } } } for (int32 i = 0; i < EffectCardsPanel->EffectCardGroups.Num(); ++i) { + if (!EffectCardsPanel->EffectCardGroups[i].bIsDedicated) + { + if (EffectCardsPanel->EffectCardGroups[i].bIsActive) + { + return TEXT("特效组_") + EffectCardsPanel->EffectCardGroups[i].GroupName; + } + } for (int32 j = 0; j < EffectCardsPanel->EffectCardGroups[i].Cards.Num(); ++j) { if (EffectCardsPanel->EffectCardGroups[i].Cards[j].bIsActive) { - return EffectCardsPanel->EffectCardGroups[i].Cards[j].Name; + return TEXT("特效卡_") + EffectCardsPanel->EffectCardGroups[i].Cards[j].Name; } } } diff --git a/Source/Cut5/Widgets/SCutTimeline.cpp b/Source/Cut5/Widgets/SCutTimeline.cpp index 59c5b3d..f50ba22 100644 --- a/Source/Cut5/Widgets/SCutTimeline.cpp +++ b/Source/Cut5/Widgets/SCutTimeline.cpp @@ -297,7 +297,7 @@ void SCutTimeline::Construct(const FArguments& InArgs) + SHorizontalBox::Slot() .SizeParam(FStretch(0.93f)) [ - SNew(SVerticalBox) + SAssignNew(TimelineMainContentVerticalBox, SVerticalBox) + SVerticalBox::Slot() .SizeParam(FAuto()) [ @@ -518,6 +518,13 @@ TArray SCutTimeline::GetClipData() return ResultClipData; } +FReply SCutTimeline::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) +{ + FVector2D Vector = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()); + GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Red, FString::Printf(TEXT("X:%f,Y:%f"), Vector.X, Vector.Y)); + return SCompoundWidget::OnMouseMove(MyGeometry, MouseEvent); +} + int32 SCutTimeline::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const diff --git a/Source/Cut5/Widgets/SCutTimeline.h b/Source/Cut5/Widgets/SCutTimeline.h index 8cc6696..bcd6c9e 100644 --- a/Source/Cut5/Widgets/SCutTimeline.h +++ b/Source/Cut5/Widgets/SCutTimeline.h @@ -77,10 +77,12 @@ public: void SetAutoPlay(bool bStart); void IterateCursor(); FTickCursorTimeThread* TickCursorTimeThread = nullptr; + TSharedPtr TimelineMainContentVerticalBox; TSharedPtr CommandList; TArray GetClipData(); + virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; FTimerHandle TimerHandle; bool AutoPlaying = false; virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override; @@ -171,6 +173,7 @@ public: int32 FPS = 0; TFunction BindFunction; bool bIsDead = false; + FString Guid = FGuid::NewGuid().ToString(); virtual uint32 Run() override { while (!bIsDead) @@ -179,7 +182,8 @@ public: { FPlatformProcess::Sleep(1.0f / FPS); FFunctionGraphTask::CreateAndDispatchWhenReady([this]() - { + { + UE_LOG(LogTemp, Warning, TEXT("%s Tick"), *Guid); if (BindFunction) BindFunction(); }, TStatId(), nullptr, ENamedThreads::GameThread); diff --git a/Source/Cut5/Widgets/STimelineClip.cpp b/Source/Cut5/Widgets/STimelineClip.cpp index 6d6e4fa..11e1e7c 100644 --- a/Source/Cut5/Widgets/STimelineClip.cpp +++ b/Source/Cut5/Widgets/STimelineClip.cpp @@ -79,6 +79,11 @@ FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const F MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().AddCursorHere); } + if (ClipData->ClipType == ETrackType::AtomSphereLightTrack) + { + MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().FillPlayers); + } + MenuContent = MenuBuilder.MakeWidget(); FSlateApplication::Get().PushMenu(AsShared(), FWidgetPath(), MenuContent.ToSharedRef(), FSlateApplication::Get().GetCursorPos(), FPopupTransitionEffect::ContextMenu); @@ -385,6 +390,41 @@ void STimelineClip::Seek(int32 Frame) const int32 SeekMovieFrame = ClipData->VideoStartFrame + Offset; + if (MainWidgetInterface->GetSelf()->GetThread(FUtils::GetVideoThreadGuid(ClipData->ClipGuid))) + { + static_cast(MainWidgetInterface->GetSelf()->GetThread(FUtils::GetVideoThreadGuid(ClipData->ClipGuid)))->SeekFrame(SeekMovieFrame); + } + + if (ClipData->PresetsCustomData.PresetCustomType != FPresetsCustomData::EPresetCustomType::None) + { + if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Breathe) + { + MainWidgetInterface->OnUpdateLightArray(FUtils::SingleColor2ColorArray(ClipData->GetBreathColor(SeekMovieFrame))); + } + else if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Flash) + { + MainWidgetInterface->OnUpdateLightArray(FUtils::SingleColor2ColorArray(ClipData->GetFlashColor(SeekMovieFrame))); + } + else if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Gradient) + { + MainWidgetInterface->OnUpdateLightArray(FUtils::SingleColor2ColorArray(ClipData->GetGradientColor(SeekMovieFrame))); + } + break; + } + else if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::None + && !ClipData->ResourcePropertyDataPtr) + { + MainWidgetInterface->OnUpdateLightArray(FUtils::SingleColor2ColorArray(ClipData->ClipColors[0].ToFColor(false))); + } + break; + + } + case ETrackType::LightBarTrack: + { + const int32 Offset = Frame - ClipData->ClipStartFrame; + const int32 SeekMovieFrame = ClipData->VideoStartFrame + Offset; + + if (MainWidgetInterface->GetSelf()->GetThread(FUtils::GetVideoThreadGuid(ClipData->ClipGuid))) { static_cast(MainWidgetInterface->GetSelf()->GetThread(FUtils::GetVideoThreadGuid(ClipData->ClipGuid)))->SeekFrame(SeekMovieFrame); @@ -454,7 +494,7 @@ void STimelineClip::Seek(int32 Frame) } else if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::None) { - MainWidgetInterface->OnUpdatePlayers(Body, ClipData->ClipColors[0].ToFColor(false)); + MainWidgetInterface->OnUpdatePlayers(Body, ClipData->PresetsCustomData.Colors[0].ToFColor(false)); } break; } @@ -607,67 +647,117 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe if (ClipData->ClipType == ETrackType::AudioTrack || ClipData->ClipType == ETrackType::AudioTrackR) { const FSlateBrush Brush; - - float DownSample = 4; + // Draw Audio Waveform - - - const float RangeStart = MainWidgetInterface->GetCutTimeline()->TrackBodyHScrollBox->GetCachedGeometry().LocalToAbsolute(FVector2D(0, 0)).X; - const float RangeEnd = MainWidgetInterface->GetCutTimeline()->TrackBodyHScrollBox->GetCachedGeometry().LocalToAbsolute(FVector2D(MainWidgetInterface->GetCutTimeline()->TrackBodyHScrollBox->GetCachedGeometry().GetLocalSize().X, 0)).X; + const float RangeStart = // MainWidgetInterface->GetCutTimeline()->TrackBodyHScrollBox->GetCachedGeometry().GetLocalPositionAtCoordinates(FVector2D(0, 0)).X; + // MainWidgetInterface->GetSelf()->GetCachedGeometry().GetLocalPositionAtCoordinates(MainWidgetInterface->GetCutTimeline()->TimelineMainContentVerticalBox->GetCachedGeometry().GetLocalPositionAtCoordinates(FVector2D(0, 0))).X; + MainWidgetInterface->GetCutTimeline()->TimelineMainContentVerticalBox->GetCachedGeometry().Position.X; + const float RangeEnd = // MainWidgetInterface->GetCutTimeline()->TrackBodyScrollBox->GetCachedGeometry().GetLocalPositionAtCoordinates(FVector2D(MainWidgetInterface->GetCutTimeline()->TrackBodyScrollBox->GetCachedGeometry().GetLocalSize().X, 0)).X; + MainWidgetInterface->GetCutTimeline()->TimelineMainContentVerticalBox->GetCachedGeometry().GetLocalSize().X; const float CurrentStartRange = AllottedGeometry.LocalToAbsolute(FVector2D(0, 0)).X; const float CurrentEndRange = AllottedGeometry.LocalToAbsolute(FVector2D(AllottedGeometry.GetLocalSize().X, 0)).X; + + + int32 CropStartFrameOffset = ((CurrentStartRange * -1) + RangeStart > 0 ? (CurrentStartRange * -1) + RangeStart : 0) / FGlobalData::DefaultTimeTickSpace; + if (CurrentEndRange < RangeStart) + { + CropStartFrameOffset = -1; + } - const int32 CropStartFrameOffset = ((CurrentStartRange * -1) + RangeStart > 0 ? (CurrentStartRange * -1) + RangeStart : 0) / FGlobalData::DefaultTimeTickSpace; const int32 CropEndFrameOffset = (RangeEnd - CurrentEndRange > 0 ? - (RangeEnd - RangeStart) + CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace : CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace + (RangeEnd - RangeStart)) + (CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace) + (RangeEnd - RangeStart) - (RangeEnd - CurrentEndRange) : CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace + (RangeEnd - RangeStart)) / FGlobalData::DefaultTimeTickSpace; - + int32 NeedDrawCount = (CropEndFrameOffset - CropStartFrameOffset) * FGlobalData::DefaultTimeTickSpace; - - - + GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Red, FString::Printf(TEXT("CropStartFrameOffset : %d"), CropStartFrameOffset)); + GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Red, FString::Printf(TEXT("CropEndFrameOffset : %d"), CropEndFrameOffset)); + + const int32 StartOffset = (ClipData->ResourcePropertyDataPtr->AudioSample / FGlobalData::GlobalFPS) * ClipData->VideoStartFrame * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat) * 2 / DownSample; - - const int32 EndOffset = (ClipData->ResourcePropertyDataPtr->AudioSample / FGlobalData::GlobalFPS) + const int32 EndOffset = (ClipData->ResourcePropertyDataPtr->AudioSample / FGlobalData::GlobalFPS) * ClipData->VideoEndFrame * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat) * 2 / DownSample; - + const int32 CropStartDataOffset = (ClipData->ResourcePropertyDataPtr->AudioSample / FGlobalData::GlobalFPS) * CropStartFrameOffset * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat) * 2 / DownSample; - + const int32 CropEndDataOffset = (ClipData->ResourcePropertyDataPtr->AudioSample / FGlobalData::GlobalFPS) * CropEndFrameOffset * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat) * 2 / DownSample; - - const int32 Interval = ((EndOffset + CropEndDataOffset) - (StartOffset + CropStartDataOffset)) / NeedDrawCount; - - GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Red, FString::FromInt(NeedDrawCount)); - GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Green, FString::FromInt(Interval)); - - - for (int32 i = 0; i < NeedDrawCount / DownSample; i++) + if (NeedDrawCount == 0) { - const int32 CurrentIndex = (StartOffset * DownSample) + (i * (Interval * DownSample * 4)); - if (CurrentIndex >= ClipData->ResourcePropertyDataPtr->AudioData.Num()) - continue; - - float NewFloat = *reinterpret_cast(&ClipData->ResourcePropertyDataPtr->AudioData[CurrentIndex]); - float Y = FMath::GetMappedRangeValueClamped(FVector2D(1.0, 0.0), FVector2D(0.0, AllottedGeometry.GetLocalSize().Y), - FMath::Abs(NewFloat)); - TArray NewLoc; - NewLoc.Add(FVector2D((CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace + i) * DownSample, AllottedGeometry.GetLocalSize().Y)); - NewLoc.Add(FVector2D((CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace + i) * DownSample, Y)); - FSlateDrawElement::MakeLines(OutDrawElements, LayerId + 6, AllottedGeometry.ToPaintGeometry(), NewLoc, ESlateDrawEffect::None, - FColor(45, 214, 153, 255), true, DownSample * 1.2); + NeedDrawCount = -1; } + const int32 Interval = (CropEndDataOffset - CropStartDataOffset) / NeedDrawCount; + + + GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Red, FString::FromInt(NeedDrawCount)); + GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Green, FString::FromInt(Interval)); + + if (CropStartFrameOffset != -1 || NeedDrawCount != -1) + { + for (int32 i = 0; i < NeedDrawCount / DownSample; i++) + { + const int32 CurrentIndex = (CropStartDataOffset * DownSample) + (i * (Interval * DownSample * 4)); + if (CurrentIndex >= ClipData->ResourcePropertyDataPtr->AudioData.Num()) + continue; + + float NewFloat = *reinterpret_cast(&ClipData->ResourcePropertyDataPtr->AudioData[CurrentIndex]); + float Y = FMath::GetMappedRangeValueClamped(FVector2D(1.0, 0.0), FVector2D(0.0, AllottedGeometry.GetLocalSize().Y), + FMath::Abs(NewFloat)); + TArray NewLoc; + NewLoc.Add(FVector2D((CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace + i * DownSample) , AllottedGeometry.GetLocalSize().Y)); + NewLoc.Add(FVector2D((CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace + i * DownSample) , Y)); + // GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Red, NewLoc[0].ToString()); + FSlateDrawElement::MakeLines(OutDrawElements, LayerId + 6, AllottedGeometry.ToPaintGeometry(), NewLoc, ESlateDrawEffect::None, + FColor(45, 214, 153, 255), true, DownSample * 1.2); + } + } + + + // + // int32 NeedDrawCount = ClipData->GetLength() * FGlobalData::DefaultTimeTickSpace; + // float DownSample = 4; + // // Draw Audio Waveform + // + // + // const float RangeStart = MainWidgetInterface->GetCutTimeline()->TrackBodyHScrollBox->GetCachedGeometry().LocalToAbsolute(FVector2D(0, 0)).X; + // const float RangeEnd = MainWidgetInterface->GetCutTimeline()->TrackBodyHScrollBox->GetCachedGeometry().LocalToAbsolute(FVector2D(MainWidgetInterface->GetCutTimeline()->TrackBodyHScrollBox->GetCachedGeometry().GetLocalSize().X, 0)).X; + // const float CurrentStartRange = AllottedGeometry.LocalToAbsolute(FVector2D(0, 0)).X; + // const float CurrentEndRange = AllottedGeometry.LocalToAbsolute(FVector2D(AllottedGeometry.GetLocalSize().X, 0)).X; + // + // const int32 StartOffset = (ClipData->ResourcePropertyDataPtr->AudioSample / FGlobalData::GlobalFPS) + // * ClipData->VideoStartFrame + // * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat) * 2 / DownSample; + // + // const int32 EndOffset = (ClipData->ResourcePropertyDataPtr->AudioSample / FGlobalData::GlobalFPS) + // * ClipData->VideoEndFrame + // * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat) * 2 / DownSample; + // + // const int32 Interval = (EndOffset - StartOffset) / NeedDrawCount; + // for (int32 i = 0; i < NeedDrawCount / DownSample; i++) + // { + // const int32 CurrentIndex = (StartOffset * DownSample) + (i * (Interval * DownSample * 4)); + // if (CurrentIndex >= ClipData->ResourcePropertyDataPtr->AudioData.Num()) + // continue; + // + // float NewFloat = *reinterpret_cast(&ClipData->ResourcePropertyDataPtr->AudioData[CurrentIndex]); + // float Y = FMath::GetMappedRangeValueClamped(FVector2D(1.0, 0.0), FVector2D(0.0, AllottedGeometry.GetLocalSize().Y), + // FMath::Abs(NewFloat)); + // TArray NewLoc; + // NewLoc.Add(FVector2D(i * DownSample, AllottedGeometry.GetLocalSize().Y)); + // NewLoc.Add(FVector2D(i * DownSample, Y)); + // FSlateDrawElement::MakeLines(OutDrawElements, LayerId + 6, AllottedGeometry.ToPaintGeometry(), NewLoc, ESlateDrawEffect::None, + // FColor(45, 214, 153, 255), true, DownSample * 1.2); + // } FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 5, AllottedGeometry.ToPaintGeometry(), &Brush, ESlateDrawEffect::None, FColor(22, 105, 78, 255)); } @@ -690,7 +780,8 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe } - if (ClipData->MovieBrushNum > 0) + if (ClipData->MovieBrushNum > 0 && (ClipData->ClipType == ETrackType::VideoTrack || ClipData->ClipType == ETrackType::LightArrayTrack || + ClipData->ClipType == ETrackType::LightBarTrack)) { int32 Step = ClipData->MovieBrushNum; @@ -726,11 +817,11 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe if (ClipData->PresetType == EPresetType::EnableProjector) { - FSlateDrawElement::MakeText(OutDrawElements, LayerId + 9, AllottedGeometry.ToPaintGeometry(), FText::FromString(TEXT("开启投影仪")), FAppStyle::Get().GetWidgetStyle("NormalText").Font, ESlateDrawEffect::None, FLinearColor::White); + FSlateDrawElement::MakeText(OutDrawElements, LayerId + 9, AllottedGeometry.ToPaintGeometry(), FText::FromString(TEXT("开启\n投影仪")), FAppStyle::Get().GetWidgetStyle("NormalText").Font, ESlateDrawEffect::None, FLinearColor::White); } if (ClipData->PresetType == EPresetType::DisableProjector) { - FSlateDrawElement::MakeText(OutDrawElements, LayerId + 9, AllottedGeometry.ToPaintGeometry(), FText::FromString(TEXT("关闭投影仪")), FAppStyle::Get().GetWidgetStyle("NormalText").Font, ESlateDrawEffect::None, FLinearColor::White); + FSlateDrawElement::MakeText(OutDrawElements, LayerId + 9, AllottedGeometry.ToPaintGeometry(), FText::FromString(TEXT("关闭\n投影仪")), FAppStyle::Get().GetWidgetStyle("NormalText").Font, ESlateDrawEffect::None, FLinearColor::White); } if (ClipData->bIsCycle == true) { @@ -782,7 +873,8 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe } - if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::None) + if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::None +&& ClipData->ClipType != ETrackType::AudioTrackR && ClipData->ClipType != ETrackType::AudioTrack) { const FSlateBrush Brush; FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 4, AllottedGeometry.ToPaintGeometry(), diff --git a/Source/Cut5/Widgets/STrackBody.cpp b/Source/Cut5/Widgets/STrackBody.cpp index d22df45..af6fb78 100644 --- a/Source/Cut5/Widgets/STrackBody.cpp +++ b/Source/Cut5/Widgets/STrackBody.cpp @@ -53,6 +53,11 @@ void STrackBody::Construct(const FArguments& InArgs) { AddVolume(SelectedClipGUID); }), FCanExecuteAction()); + CommandList->MapAction(FTimelineClipCommands::Get().FillPlayers, FExecuteAction::CreateLambda([this]() + { + FillPlayers(SelectedClipGUID); + }), FCanExecuteAction()); + MainWidgetInterface = InArgs._MainWidgetInterface; TrackHead = InArgs._TrackHead; ChildSlot @@ -136,6 +141,7 @@ FReply STrackBody::OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& return SCompoundWidget::OnDragOver(MyGeometry, DragDropEvent); } + void STrackBody::OnDragEnter(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) { @@ -274,6 +280,33 @@ void STrackBody::Fill2End(const FGuid& Guid) } } +void STrackBody::FillPlayers(const FGuid& Guid) +{ + FClipData NewClipData; + for (int32 i = 0; i < SlateClips.Num(); i++) + { + if (TrackHead->TrackData.ClipData[i].ClipGuid == Guid) + { + NewClipData = TrackHead->TrackData.ClipData[i]; + } + } + for (FSingleTrackGroupInstance& Instance : MainWidgetInterface->GetCutTimeline()->TrackGroupInstances) + { + TSharedPtr TrackBody = StaticCastSharedPtr(Instance.Body); + if (TrackBody->TrackHead != TrackHead) + { + if (TrackBody->TrackHead->TrackData.TrackType == ETrackType::AtomSphereLightTrack) + { + NewClipData.ClipGuid = FGuid::NewGuid(); + NewClipData.BindTrackGuid = TrackBody->TrackHead->TrackData.DeviceTrack.Guid; + DragDropOperator::GetDragDropOperator()->UpdateClipProcess(MainWidgetInterface, NewClipData); + TrackBody->TrackHead->TrackData.ClipData.Add(NewClipData); + TrackBody->CallRender(); + } + } + } +} + void STrackBody::SetCycle(const FGuid& Guid, bool Cycle) { for (int32 i = 0; i < SlateClips.Num(); i++) diff --git a/Source/Cut5/Widgets/STrackBody.h b/Source/Cut5/Widgets/STrackBody.h index 825d3f9..c3c5442 100644 --- a/Source/Cut5/Widgets/STrackBody.h +++ b/Source/Cut5/Widgets/STrackBody.h @@ -36,6 +36,7 @@ public: virtual void BreakClip(const FGuid& Guid) override; void Fill2Start(const FGuid& Guid); void Fill2End(const FGuid& Guid); + void FillPlayers(const FGuid& Guid); void SetCycle(const FGuid& Guid, bool Cycle); void AddCursor(const FGuid& Guid); void AddVolume(const FGuid& Guid); @@ -59,3 +60,4 @@ public: }; + diff --git a/Source/Cut5/Widgets/StatePanel/SLightArrayPanel.cpp b/Source/Cut5/Widgets/StatePanel/SLightArrayPanel.cpp index cd1288a..20a7b80 100644 --- a/Source/Cut5/Widgets/StatePanel/SLightArrayPanel.cpp +++ b/Source/Cut5/Widgets/StatePanel/SLightArrayPanel.cpp @@ -15,6 +15,7 @@ BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION void SLightArrayPanel::Construct(const FArguments& InArgs) { LightGridColors.Init(FColor(255, 0, 0, 255), FGlobalData::LightArrayX * FGlobalData::LightArrayY); + LightBarColors.Init(FColor(0, 0, 0, 255), FGlobalData::LightArrayX * FGlobalData::LightArrayY); ChildSlot [ @@ -95,6 +96,31 @@ int32 SLightArrayPanel::OnPaint(const FPaintArgs& Args, const FGeometry& Allotte } } + for (int32 i = 0; i < FGlobalData::LightArrayX; i++) + { + const FSlateBrush Brush; + FSlateDrawElement::MakeBox( + OutDrawElements, + LayerId + 100000, + LightBar1->GetPaintSpaceGeometry().ToPaintGeometry(SingleLocalSize, FSlateLayoutTransform(FVector2D(i * OriginLocalSize.X, OriginLocalSize.Y))), + &Brush, + ESlateDrawEffect::None, + LightBarColors[i] + ); + } + + for (int32 i = 0; i < FGlobalData::LightArrayX; i++) + { + const FSlateBrush Brush; + FSlateDrawElement::MakeBox( + OutDrawElements, + LayerId + 100000, + LightBar2->GetPaintSpaceGeometry().ToPaintGeometry(SingleLocalSize, FSlateLayoutTransform(FVector2D(i * OriginLocalSize.X, OriginLocalSize.Y))), + &Brush, + ESlateDrawEffect::None, + LightBarColors[i] + ); + } return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled); } diff --git a/Source/Cut5/Widgets/StatePanel/SLightArrayPanel.h b/Source/Cut5/Widgets/StatePanel/SLightArrayPanel.h index 0814d52..c3c19b6 100644 --- a/Source/Cut5/Widgets/StatePanel/SLightArrayPanel.h +++ b/Source/Cut5/Widgets/StatePanel/SLightArrayPanel.h @@ -27,4 +27,5 @@ public: TSharedPtr LightBar1; TSharedPtr LightBar2; TArray LightGridColors; + TArray LightBarColors; }; diff --git a/Source/Cut5/Widgets/StaticProperties/ClipProperties.cpp b/Source/Cut5/Widgets/StaticProperties/ClipProperties.cpp new file mode 100644 index 0000000..09e0da1 --- /dev/null +++ b/Source/Cut5/Widgets/StaticProperties/ClipProperties.cpp @@ -0,0 +1,674 @@ +// #include "ClipProperties.h" +// +// #include "Cut5/Utils/Utils.h" +// #include "Cut5/Widgets/SCutTimeline.h" +// #include "Cut5/Widgets/STrackHead.h" +// +// +// FClipProperties* FClipProperties::GetProperties() +// { +// static FClipProperties* Properties = new FClipProperties(); +// return Properties; +// } +// +// TSharedPtr FClipProperties::GetProperties(ICutMainWidgetInterface* MainInterface) +// { +// Selectable.Empty(); +// Selectable.Add(MakeShared(TEXT("无"))); +// Selectable.Add(MakeShared(TEXT("呼吸"))); +// Selectable.Add(MakeShared(TEXT("闪烁"))); +// Selectable.Add(MakeShared(TEXT("渐变"))); +// +// +// FTextBlockStyle NormalText = FAppStyle::GetWidgetStyle("NormalText"); +// NormalText.SetFontSize(13); +// +// TSharedPtr VerticalBox; +// +// PropertiesWidget = SAssignNew(VerticalBox, SVerticalBox); +// +// +// +// if (!IsEqualPresetType(GetClips(MainInterface), EPresetType::NotAPresets) +// && !IsEqualTrackType(GetClips(MainInterface), ETrackType::VolumeTrack)) +// { // 颜色 +// 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(SImage) +// .Image(FUtils::GetBrushFromImage(FUtils::GetResourcesPath("Color.png"), {})) +// .ColorAndOpacity_Lambda([this, MainInterface]() +// { +// if (GetClips(MainInterface).Num() > 0) +// { +// return GetClips(MainInterface)[0]->PresetsCustomData.Colors[0]; +// } +// else +// { +// return FLinearColor::White; +// } +// }) +// .OnMouseButtonDown_Lambda([this, MainInterface](const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) +// { +// MainInterface->OpenColorPanel(&ClipData->PresetsCustomData.Colors[0]); +// return FReply::Handled(); +// }) +// ] +// ] +// ] +// ]; +// +// +// // 动效 +// 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(SComboBox>) +// .OptionsSource(&Selectable) +// .OnGenerateWidget_Lambda([this](TSharedPtr InItem) +// { +// return SNew(STextBlock).Text(FText::FromString(*InItem)); +// }) +// .OnSelectionChanged_Lambda([this](TSharedPtr 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("闪烁")); +// }) +// ] +// ] +// ] +// ] +// ]; +// +// // 次数 +// 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) +// .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; +// }) +// ] +// ] +// ] +// ]; +// +// +// // 时间 +// 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) +// .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>(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 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) +// ] +// ] +// ]; +// } +// +// if ((ClipData->ClipType == ETrackType::AudioTrack || ClipData->ClipType == ETrackType::AudioTrackR) && MainInterface->GetSelf()->GetCurrentSelectCurtain() != FGuid()) +// { +// +// AudiosCurtainOptions.Empty(); +// TArray& Groups = MainInterface->GetSelf()->CurtainPanel->Groups; +// for (FCurtainGroup& Group : Groups) +// { +// for (FCurtain& Curtain : Group.Curtains) +// { +// if (Curtain.CurtainUUID != MainInterface->GetSelf()->GetCurrentSelectCurtain()) +// { +// AudiosCurtainOptions.Add(MakeShared(Curtain.CurtainName, Curtain.CurtainUUID)); +// } +// } +// } +// +// for (FEffectCardGroup& CardGroup : MainInterface->GetSelf()->EffectCardsPanel->EffectCardGroups) +// { +// if (!CardGroup.bIsDedicated) +// { +// AudiosCurtainOptions.Add(MakeShared(CardGroup.GroupName, CardGroup.Guid)); +// } +// +// +// for (FEffectCardProperty& CardProperty : CardGroup.Cards) +// { +// if (!CardProperty.IsClone) +// { +// AudiosCurtainOptions.Add(MakeShared(CardProperty.Name, CardProperty.Guid)); +// } +// } +// } +// +// VerticalBox->AddSlot() +// .Padding(0, 16, 0 ,0) +// [ +// SNew(SBox).HeightOverride(32).WidthOverride(214) +// [ +// SNew(SHorizontalBox) +// + SHorizontalBox::Slot() +// .SizeParam(FAuto()) +// .VAlign(VAlign_Center) +// [ +// SNew(SBox) +// .VAlign(VAlign_Center) +// .WidthOverride(62) +// .HeightOverride(32) +// [ +// SNew(STextBlock) +// .Text(FText::FromString(TEXT("有效幕"))) +// .Font(NormalText.Font) +// .Justification(ETextJustify::Center) +// ] +// ] +// + SHorizontalBox::Slot() +// .SizeParam(FAuto()) +// [ +// SNew(SBox) +// .WidthOverride(136) +// .HeightOverride(32) +// [ +// SAssignNew(AudiosCurtainComboBox, SComboBox>) +// .OptionsSource(&AudiosCurtainOptions) +// .OnGenerateWidget_Lambda([this](TSharedPtr InItem) +// { +// return SNew(SHorizontalBox) +// + SHorizontalBox::Slot() +// [ +// SNew(STextBlock).Text(FText::FromString(*InItem->String)) +// ] +// + SHorizontalBox::Slot() +// .HAlign(HAlign_Right) +// [ +// SNew(SCheckBox) +// .IsChecked(ClipData->AudioCurtains.Contains(*InItem.Get()) ? ECheckBoxState::Checked : ECheckBoxState::Unchecked) +// .OnCheckStateChanged_Lambda([this, InItem](const ECheckBoxState& State) +// { +// const FGuid& Guid = InItem.Get()->Guid; +// FCurtainGroup* Group = nullptr; +// const FString CurrentPath = // MainInterface->GetSelf()->CurtainPanel->FindCurtain(Guid,Group)->TimelineInfo.CurrentOpenFullPath; +// MainInterface->GetSelf()->GetSelectTimelineInfoByGuid(Guid).CurrentOpenFullPath; +// FTimelineLoader TimelineLoader(CurrentPath, true); +// if (TimelineLoader.GetSpecifyClipData(ClipData->ClipType).Num() > 0 && State == ECheckBoxState::Checked) +// { +// FUtils::AddTips( +// SNew(STips) +// .Title(TEXT("警告")) +// .SubTitle(TEXT("选中的幕中的音频轨道已经存在音频片段\n如果继续添加,将会覆盖原有的音频片段\n是否继续?")) +// .OnEnsure_Lambda([this, State, InItem, CurrentPath](const FString& String) +// { +// // 先清空 +// FTimelineLoader ModifyTimelineLoader(CurrentPath, true); +// TArray Clips = ModifyTimelineLoader.GetSpecifyClipData(ClipData->ClipType); +// for (int32 i = Clips.Num() - 1; i >= 0; i--) +// { +// ModifyTimelineLoader.RemoveClipData(Clips[i]); +// } +// +// FClipData NewClip = *ClipData; +// NewClip.Move(0); +// NewClip.bIsVirtual = true; +// NewClip.VirtualCurtainGuid = MainInterface->GetSelf()->GetCurrentSelectCurtain(); +// NewClip.ClipGuid = FGuid::NewGuid(); +// ModifyTimelineLoader.GetClipData().Add(NewClip); +// +// if (State == ECheckBoxState::Checked) +// { +// ClipData->AudioCurtains.Add(*InItem.Get()); +// MainInterface->UpdateProperties(this); +// } +// else +// { +// ClipData->AudioCurtains.Remove(*InItem.Get()); +// MainInterface->UpdateProperties(this); +// } +// }) +// ); +// } +// else +// { +// if (State == ECheckBoxState::Checked) +// { +// FClipData NewClip = *ClipData; +// NewClip.Move(0); +// NewClip.bIsVirtual = true; +// NewClip.VirtualCurtainGuid = MainInterface->GetSelf()->GetCurrentSelectCurtain(); +// NewClip.ClipGuid = FGuid::NewGuid(); +// TimelineLoader.GetClipData().Add(NewClip); +// +// +// ClipData->AudioCurtains.Add(*InItem.Get()); +// MainInterface->UpdateProperties(this); +// +// +// } +// else +// { +// if (TimelineLoader.GetSpecifyClipData(ClipData->ClipType).Num() > 0) +// { +// TArray Clips = TimelineLoader.GetSpecifyClipData(ClipData->ClipType); +// for (int32 i = Clips.Num() - 1; i >= 0; i--) +// { +// TimelineLoader.RemoveClipData(Clips[i]); +// } +// } +// +// +// ClipData->AudioCurtains.Remove(*InItem.Get()); +// MainInterface->UpdateProperties(this); +// } +// } +// +// +// +// +// +// }) +// ]; +// +// }) +// [ +// SNew(STextBlock).Text_Lambda([this]() +// { +// if (ClipData->AudioCurtains.Num() == 1) +// { +// return FText::FromString(ClipData->AudioCurtains[0].String); +// } +// else if (ClipData->AudioCurtains.Num() > 1) +// { +// return FText::FromString(TEXT("多个")); +// } +// else +// { +// return FText::FromString(TEXT("无")); +// } +// }) +// ] +// ] +// ] +// ] +// ]; +// } +// +// if (ClipData->ClipType == ETrackType::VolumeTrack) +// { +// 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()) +// .HAlign(HAlign_Right) +// [ +// SNew(SBox) +// .WidthOverride(136) +// .HeightOverride(32) +// [ +// SNew(SCheckBox) +// .IsChecked_Lambda([this]() +// { +// return ClipData->Work4Audio ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; +// }) +// .OnCheckStateChanged_Lambda([this](const ECheckBoxState State) +// { +// ClipData->Work4Audio = State == ECheckBoxState::Checked; +// }) +// ] +// ] +// ] +// ]; +// +// 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()) +// .HAlign(HAlign_Right) +// [ +// SNew(SBox) +// .WidthOverride(136) +// .HeightOverride(32) +// [ +// SNew(SCheckBox) +// .IsChecked_Lambda([this]() +// { +// return ClipData->Work4Video ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; +// }) +// .OnCheckStateChanged_Lambda([this](const ECheckBoxState State) +// { +// ClipData->Work4Video = State == ECheckBoxState::Checked; +// }) +// ] +// ] +// ] +// ]; +// +// 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) +// .Value_Lambda([this]() +// { +// if (!ClipData) +// return 0; +// return ClipData->CurrentVolume; +// }) +// .MinValue(1) +// .MaxValue(100) +// .OnValueChanged_Lambda([this](const int32& Value) +// { +// if (!ClipData) +// return; +// ClipData->CurrentVolume = Value; +// }) +// ] +// ] +// ] +// ]; +// } +// +// +// +// return PropertiesWidget; +// } +// +// TArray FClipProperties::GetClips(ICutMainWidgetInterface* MainInterface) +// { +// TArray Clips; +// for (FSingleTrackGroupInstance& Instance : MainInterface->GetCutTimeline()->TrackGroupInstances) +// { +// for (FClipData& ClipData: StaticCastSharedPtr(Instance.Head)->TrackData.ClipData) +// { +// if (MainInterface->GetCutTimeline()->SelectedClips.Contains(ClipData.ClipGuid)) +// { +// Clips.Add(&ClipData); +// } +// } +// } +// return Clips; +// } +// +// bool FClipProperties::IsEqualTrackType(TArray ClipData, ETrackType Type) +// { +// for (FClipData* Data : ClipData) +// { +// if (Data->ClipType != Type) +// return false; +// } +// return true; +// } +// bool FClipProperties::IsEqualPresetType(TArray ClipData, EPresetType Type) +// { +// for (FClipData* Data : ClipData) +// { +// if (Data->PresetType != Type) +// return false; +// } +// return true; +// } diff --git a/Source/Cut5/Widgets/StaticProperties/ClipProperties.h b/Source/Cut5/Widgets/StaticProperties/ClipProperties.h new file mode 100644 index 0000000..df6792e --- /dev/null +++ b/Source/Cut5/Widgets/StaticProperties/ClipProperties.h @@ -0,0 +1,16 @@ +// #pragma once +// #include "Cut5/Interface/CutMainWidgetInterface.h" +// +// class FClipProperties +// { +// public: +// static FClipProperties* GetProperties(); +// TSharedPtr GetProperties(ICutMainWidgetInterface* MainInterface); +// TArray GetClips(ICutMainWidgetInterface* MainInterface); +// bool IsEqualTrackType(TArray ClipData, ETrackType Type); +// bool IsEqualPresetType(TArray ClipData, EPresetType Type); +// TArray> Selectable; +// +// TSharedPtr PropertiesWidget; +// }; +// diff --git a/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp b/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp index 3220299..85ded73 100644 --- a/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp +++ b/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp @@ -349,6 +349,23 @@ TSharedPtr FClipProxy::GetPropertiesWidget() } } + for (FEffectCardGroup& CardGroup : MainInterface->GetSelf()->EffectCardsPanel->EffectCardGroups) + { + if (!CardGroup.bIsDedicated) + { + AudiosCurtainOptions.Add(MakeShared(CardGroup.GroupName, CardGroup.Guid)); + } + + + for (FEffectCardProperty& CardProperty : CardGroup.Cards) + { + if (!CardProperty.IsClone) + { + AudiosCurtainOptions.Add(MakeShared(CardProperty.Name, CardProperty.Guid)); + } + } + } + VerticalBox->AddSlot() .Padding(0, 16, 0 ,0) [ @@ -395,7 +412,8 @@ TSharedPtr FClipProxy::GetPropertiesWidget() { const FGuid& Guid = InItem.Get()->Guid; FCurtainGroup* Group = nullptr; - const FString CurrentPath = MainInterface->GetSelf()->CurtainPanel->FindCurtain(Guid,Group)->TimelineInfo.CurrentOpenFullPath; + const FString CurrentPath = // MainInterface->GetSelf()->CurtainPanel->FindCurtain(Guid,Group)->TimelineInfo.CurrentOpenFullPath; + MainInterface->GetSelf()->GetSelectTimelineInfoByGuid(Guid).CurrentOpenFullPath; FTimelineLoader TimelineLoader(CurrentPath, true); if (TimelineLoader.GetSpecifyClipData(ClipData->ClipType).Num() > 0 && State == ECheckBoxState::Checked) { @@ -416,7 +434,7 @@ TSharedPtr FClipProxy::GetPropertiesWidget() FClipData NewClip = *ClipData; NewClip.Move(0); NewClip.bIsVirtual = true; - NewClip.VirtualCurtainName = MainInterface->GetSelf()->GetCurrentSelectFileName(); + NewClip.VirtualCurtainGuid = MainInterface->GetSelf()->GetCurrentSelectCurtain(); NewClip.ClipGuid = FGuid::NewGuid(); ModifyTimelineLoader.GetClipData().Add(NewClip); @@ -440,7 +458,7 @@ TSharedPtr FClipProxy::GetPropertiesWidget() FClipData NewClip = *ClipData; NewClip.Move(0); NewClip.bIsVirtual = true; - NewClip.VirtualCurtainName = MainInterface->GetSelf()->GetCurrentSelectFileName(); + NewClip.VirtualCurtainGuid = MainInterface->GetSelf()->GetCurrentSelectCurtain(); NewClip.ClipGuid = FGuid::NewGuid(); TimelineLoader.GetClipData().Add(NewClip);