diff --git a/Resources/EffectPanel.png b/Resources/EffectPanel.png new file mode 100644 index 0000000..1c9fb10 Binary files /dev/null and b/Resources/EffectPanel.png differ diff --git a/Resources/TrackBar.png b/Resources/TrackBar.png new file mode 100644 index 0000000..af6933a Binary files /dev/null and b/Resources/TrackBar.png differ diff --git a/Source/Cut5/Cut5.Build.cs b/Source/Cut5/Cut5.Build.cs index 3c41271..9d76e13 100644 --- a/Source/Cut5/Cut5.Build.cs +++ b/Source/Cut5/Cut5.Build.cs @@ -13,7 +13,7 @@ public class Cut5 : ModuleRules PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" , "FFMPEGMedia", "FFMPEGMediaFactory"}); - PrivateDependencyModuleNames.AddRange(new string[] {"RuntimeAudioImporter", "FFMPEGMedia", "FFMPEGMediaFactory", "Slate", "SlateCore", "UMG", "OpenCV", "DesktopPlatform", "PortAudioPlugin"}); + PrivateDependencyModuleNames.AddRange(new string[] {"RuntimeAudioImporter", "FFMPEGMedia", "FFMPEGMediaFactory", "Slate", "SlateCore", "UMG", "OpenCV", "DesktopPlatform", "PortAudioPlugin", "EditorStyle"}); } } diff --git a/Source/Cut5/WidgetInterface.h b/Source/Cut5/WidgetInterface.h index 18a4f89..63fb8f7 100644 --- a/Source/Cut5/WidgetInterface.h +++ b/Source/Cut5/WidgetInterface.h @@ -25,4 +25,9 @@ public: virtual void UpdateTimelineLength() {}; virtual void Seek(int32 Frame) {}; + virtual void RemoveClip(const FGuid& Guid) {}; + virtual void BreakClip(const FGuid& Guid) {}; + + FGuid SelectedClipGUID; + int32 SelectedClipFrame; }; diff --git a/Source/Cut5/Widgets/Commands/TimelineClipCommands.cpp b/Source/Cut5/Widgets/Commands/TimelineClipCommands.cpp new file mode 100644 index 0000000..95b8b75 --- /dev/null +++ b/Source/Cut5/Widgets/Commands/TimelineClipCommands.cpp @@ -0,0 +1,9 @@ +#include "TimelineClipCommands.h" + +#define LOCTEXT_NAMESPACE "FTimelineClipCommands" +void FTimelineClipCommands::RegisterCommands() +{ + UI_COMMAND(Remove, "移除", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(Break, "分割", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord()); +} +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Source/Cut5/Widgets/Commands/TimelineClipCommands.h b/Source/Cut5/Widgets/Commands/TimelineClipCommands.h new file mode 100644 index 0000000..37f4eaa --- /dev/null +++ b/Source/Cut5/Widgets/Commands/TimelineClipCommands.h @@ -0,0 +1,22 @@ + + +#pragma once +#include "CoreMinimal.h" +#include "Framework/Commands/Commands.h" + +class FTimelineClipCommands : public TCommands +{ +public: + + FTimelineClipCommands() + : TCommands(TEXT("FTimelineClipCommands"), NSLOCTEXT("Contexts", "FTimelineClipCommands", "FTimelineClipCommands"), NAME_None, FAppStyle::GetAppStyleSetName()) + { + // 这里可以设置你的命令的默认键盘快捷键 + } + + // TCommands<> 接口 + virtual void RegisterCommands() override; + + TSharedPtr Remove; + TSharedPtr Break; +}; \ No newline at end of file diff --git a/Source/Cut5/Widgets/DefineGlobal.h b/Source/Cut5/Widgets/DefineGlobal.h index 5c0e862..fc6831d 100644 --- a/Source/Cut5/Widgets/DefineGlobal.h +++ b/Source/Cut5/Widgets/DefineGlobal.h @@ -99,7 +99,7 @@ struct CUT5_API FClipData int32 GetClipStartFrame() const { return ClipStartTime / FGlobalData::DefaultTimeTickSpace; }; int32 GetClipEndFrame() const { return ClipEndTime / FGlobalData::DefaultTimeTickSpace; }; - + int32 GetClipRelativeEndFrame() const { return GetClipEndFrame() - GetClipStartFrame(); } enum class ECropMethod @@ -112,15 +112,16 @@ struct CUT5_API FClipData if (CropMethod == ECropMethod::FromFront) { ClipStartTime += CropFrame * FGlobalData::DefaultTimeTickSpace; - if (ClipType == ETrackType::VideoTrack) + if (ClipType == ETrackType::VideoTrack || ClipType == ETrackType::AudioTrack) { VideoStartFrame += CropFrame; } + } else { ClipEndTime -= CropFrame * FGlobalData::DefaultTimeTickSpace; - if (ClipType == ETrackType::VideoTrack) + if (ClipType == ETrackType::VideoTrack || ClipType == ETrackType::AudioTrack) { VideoEndFrame -= CropFrame; } diff --git a/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp b/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp index fdcb128..a73ff94 100644 --- a/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp +++ b/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp @@ -21,10 +21,24 @@ void SEffectCardsPanel::Construct(const FArguments& InArgs) MainInterface = InArgs._MainInterface; ChildSlot [ - SNew(SBox) + SNew(SOverlay) + + SOverlay::Slot() + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) [ - SAssignNew(ScrollBox, SScrollBox) + SNew(SImage) + .Image(FUtils::GetBrushFromImage(FUtils::GetResourcesPath(TEXT("EffectPanel.png")), FVector2D(0.0, 0.0))) ] + + SOverlay::Slot() + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) + [ + SNew(SBox) + [ + SAssignNew(ScrollBox, SScrollBox) + ] + ] + ]; FEffectCardGroup DedicatedGroup; DedicatedGroup.bIsDedicated = true; diff --git a/Source/Cut5/Widgets/STimelineClip.cpp b/Source/Cut5/Widgets/STimelineClip.cpp index f37b862..c3f5e97 100644 --- a/Source/Cut5/Widgets/STimelineClip.cpp +++ b/Source/Cut5/Widgets/STimelineClip.cpp @@ -5,10 +5,13 @@ #include "AudioDevice.h" #include "RuntimeAudioImporterLibrary.h" #include "SlateOptMacros.h" +#include "Commands/TimelineClipCommands.h" #include "Cut5/WidgetInterface.h" #include "Cut5/Utils/Utils.h" #include "Engine/Engine.h" #include "Engine/Texture2D.h" +#include "Slate/Private/Framework/Application/Menu.h" + extern "C" { #include "libavformat/avformat.h" @@ -20,6 +23,21 @@ BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const FPointerEvent& PointerEvent) { + TSharedPtr MenuContent; + if (PointerEvent.IsMouseButtonDown(EKeys::RightMouseButton)) + { + Body->SelectedClipGUID = ClipData->ClipGuid; + Body->SelectedClipFrame = (Geometry.AbsoluteToLocal(PointerEvent.GetScreenSpacePosition()).X) / FGlobalData::DefaultTimeTickSpace; + FMenuBuilder MenuBuilder(true, CommandList); + MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().Remove); + MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().Break); + MenuContent = MenuBuilder.MakeWidget(); + FSlateApplication::Get().PushMenu(AsShared(), FWidgetPath(), MenuContent.ToSharedRef(), FSlateApplication::Get().GetCursorPos(), FPopupTransitionEffect::ContextMenu); + return FReply::Handled(); + } + + + const FVector2D LocalPos = Geometry.AbsoluteToLocal(PointerEvent.GetScreenSpacePosition()); // GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Blue, LocalPos.ToString()); if (LocalPos.X <= 10) @@ -43,6 +61,7 @@ FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const F void STimelineClip::Construct(const FArguments& InArgs) { + CommandList = InArgs._CommandList; ClipData = InArgs._InClipData; MainWidgetInterface = InArgs._MainWidgetInterface; Body = InArgs._Body; diff --git a/Source/Cut5/Widgets/STimelineClip.h b/Source/Cut5/Widgets/STimelineClip.h index 7661da6..80e5f9e 100644 --- a/Source/Cut5/Widgets/STimelineClip.h +++ b/Source/Cut5/Widgets/STimelineClip.h @@ -32,6 +32,7 @@ public: SLATE_ARGUMENT(FClipData*, InClipData) SLATE_ARGUMENT(ICutMainWidgetInterface*, MainWidgetInterface) SLATE_ARGUMENT(TSharedPtr, Body) + SLATE_ARGUMENT(TSharedPtr, CommandList) SLATE_END_ARGS() FReply OnBorderMouseButtonDown(const FGeometry& Geometry, const FPointerEvent& PointerEvent); @@ -50,5 +51,9 @@ public: FDecodedAudioStruct DecodedAudioStruct; PaStream* Stream = nullptr; + + + TSharedPtr CommandList; + }; diff --git a/Source/Cut5/Widgets/STrackBody.cpp b/Source/Cut5/Widgets/STrackBody.cpp index 7d54ef1..a9cdcde 100644 --- a/Source/Cut5/Widgets/STrackBody.cpp +++ b/Source/Cut5/Widgets/STrackBody.cpp @@ -4,7 +4,9 @@ #include "STrackBody.h" #include "SlateOptMacros.h" +#include "Commands/TimelineClipCommands.h" #include "Cut5/Utils/OpencvUtils.h" +#include "Cut5/Utils/Utils.h" #include "Engine/Engine.h" #include "Widgets/Layout/SConstraintCanvas.h" @@ -12,6 +14,17 @@ BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION void STrackBody::Construct(const FArguments& InArgs) { + FTimelineClipCommands::Register(); + CommandList = MakeShared(); + CommandList->MapAction(FTimelineClipCommands::Get().Remove, FExecuteAction::CreateLambda([this]() + { + RemoveClip(SelectedClipGUID); + }), FCanExecuteAction()); + CommandList->MapAction(FTimelineClipCommands::Get().Break, FExecuteAction::CreateLambda([this]() + { + BreakClip(SelectedClipGUID); + }), FCanExecuteAction()); + MainWidgetInterface = InArgs._MainWidgetInterface; TrackHead = InArgs._TrackHead; ChildSlot @@ -26,13 +39,21 @@ void STrackBody::Construct(const FArguments& InArgs) .Offset(FMargin(0, 0, 0, 0)) .Anchors(FAnchors(0, 0, 1, 1)) [ - SNew(SBorder) + SNew(SOverlay) + + SOverlay::Slot() .HAlign(HAlign_Fill) .VAlign(VAlign_Fill) - .BorderBackgroundColor(FLinearColor(0.1f, 0.15f, 0.2f, 1.0f)) [ - SAssignNew(Overlay, SOverlay) + SNew(SBorder) + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) + .BorderBackgroundColor(FLinearColor(0.1f, 0.15f, 0.2f, 1.0f)) + .BorderImage(FUtils::GetBrushFromImage(*FUtils::GetResourcesPath(TEXT("TrackBar.png")), FVector2D(0.0, 0.0))) + [ + SAssignNew(Overlay, SOverlay) + ] ] + ] ] ]; @@ -51,7 +72,7 @@ void STrackBody::CallRender() TrackHead->CutTimeline->UpdateTimelineLength(); } TSharedPtr TimelineClip; - TimelineClip = SNew(STimelineClip).InClipData(&TempClipData).MainWidgetInterface(MainWidgetInterface).Body(SharedThis(this)); + TimelineClip = SNew(STimelineClip).InClipData(&TempClipData).MainWidgetInterface(MainWidgetInterface).Body(SharedThis(this)).CommandList(CommandList); Overlay->AddSlot() .HAlign(HAlign_Left) @@ -266,6 +287,40 @@ void STrackBody::OnDragLeave(const FDragDropEvent& DragDropEvent) SCompoundWidget::OnDragLeave(DragDropEvent); } +void STrackBody::RemoveClip(const FGuid& Guid) +{ + for (int32 i = 0; i < SlateClips.Num(); i++) + { + if (TrackHead->TrackData.ClipData[i].ClipGuid == Guid) + { + TrackHead->TrackData.ClipData.RemoveAt(i); + break; + } + } + CallRender(); +} + +void STrackBody::BreakClip(const FGuid& Guid) +{ + for (int32 i = 0; i < SlateClips.Num(); i++) + { + if (TrackHead->TrackData.ClipData[i].ClipGuid == Guid) + { + FClipData NewClipData = TrackHead->TrackData.ClipData[i]; + NewClipData.ClipGuid = FGuid::NewGuid(); + + const int32 CropFrameRight = TrackHead->TrackData.ClipData[i].GetClipRelativeEndFrame() - SelectedClipFrame; + TrackHead->TrackData.ClipData[i].CropClip(FClipData::ECropMethod::FromBack, CropFrameRight); + + NewClipData.CropClip(FClipData::ECropMethod::FromFront, SelectedClipFrame + 1); + TrackHead->TrackData.ClipData.Add(NewClipData); + + GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Emerald, FString::Printf(TEXT("CropFrameLeft %d CropFrameRight %d"), SelectedClipFrame, CropFrameRight)); + } + } + CallRender(); +} + void STrackBody::Seek(int32 Frame) { for (int32 i = 0; i < SlateClips.Num(); i++) diff --git a/Source/Cut5/Widgets/STrackBody.h b/Source/Cut5/Widgets/STrackBody.h index b75dd8a..dce2dc0 100644 --- a/Source/Cut5/Widgets/STrackBody.h +++ b/Source/Cut5/Widgets/STrackBody.h @@ -28,6 +28,10 @@ public: virtual FReply OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override; virtual void OnDragEnter(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override; virtual void OnDragLeave(const FDragDropEvent& DragDropEvent) override; + + virtual void RemoveClip(const FGuid& Guid) override; + virtual void BreakClip(const FGuid& Guid) override; + TSharedPtr TrackHead; ICutMainWidgetInterface* MainWidgetInterface; TSharedPtr Overlay; @@ -40,4 +44,5 @@ public: }; virtual void Seek(int32 Frame) override; + TSharedPtr CommandList; };