diff --git a/Resources/PlayerLight.png b/Resources/PlayerLight.png new file mode 100644 index 0000000..4a29274 Binary files /dev/null and b/Resources/PlayerLight.png differ diff --git a/Source/Cut5/Interface/CutMainWidgetInterface.h b/Source/Cut5/Interface/CutMainWidgetInterface.h index 471177f..a94f2a4 100644 --- a/Source/Cut5/Interface/CutMainWidgetInterface.h +++ b/Source/Cut5/Interface/CutMainWidgetInterface.h @@ -3,6 +3,7 @@ #pragma once #include "CoreMinimal.h" +#include "Cut5/Widgets/DefineGlobal.h" #include "Engine/Texture2D.h" #include "UObject/Interface.h" #include "CutMainWidgetInterface.generated.h" @@ -26,5 +27,9 @@ public: virtual void OnUpdateVideo(FGuid UUID, UTexture2D* Texture) {}; virtual void OnUpdateLightArray(const TArray& LightArray) {}; + virtual void OnUpdatePlayers(TSharedPtr TrackBody, FColor PlayerColor) {}; + virtual void OnAddNewTrack(ETrackType Type) {}; + + virtual FString GetGroupName(TSharedPtr WidgetInterface) { return FString(); }; }; diff --git a/Source/Cut5/Utils/OpencvUtils.cpp b/Source/Cut5/Utils/OpencvUtils.cpp index ca57ab4..c27608c 100644 --- a/Source/Cut5/Utils/OpencvUtils.cpp +++ b/Source/Cut5/Utils/OpencvUtils.cpp @@ -39,11 +39,18 @@ TArray> FOpencvUtils::GetVideoFrameLightArray(FString VideoPath, TArray LightArray; VideoCapture.retrieve(Array); cv::resize(Array, Array, cv::Size(X, Y)); - for (int32 i = 0; i < Array.cols * Array.rows; i++) + uint8* RGBAData = new uint8[Array.cols * Array.rows * 4]; + for (int i = 0; i < Array.cols * Array.rows; i++) { - LightArray.Add(FColor(Array.data[i * 3 + 0], Array.data[i * 3 + 1], Array.data[i * 3 + 2], 255)); + RGBAData[i * 4 + 0] = Array.data[i * 3 + 2]; + RGBAData[i * 4 + 1] = Array.data[i * 3 + 1]; + RGBAData[i * 4 + 2] = Array.data[i * 3 + 0]; + RGBAData[i * 4 + 3] = 255; + LightArray.Add(FColor(RGBAData[i * 4 + 0], RGBAData[i * 4 + 1], RGBAData[i * 4 + 2], RGBAData[i * 4 + 3])); } + delete[] RGBAData; Colors.Add(LightArray); + } if (Array.empty()) { @@ -53,3 +60,28 @@ TArray> FOpencvUtils::GetVideoFrameLightArray(FString VideoPath, VideoCapture.release(); return Colors; } + +TArray FOpencvUtils::GetVideoSingleLightColor(FString VideoPath) +{ + cv::VideoCapture VideoCapture; + VideoCapture.open(TCHAR_TO_UTF8(*VideoPath)); + + + TArray LightArray; + while (VideoCapture.isOpened()) + { + cv::Mat Array; + if (VideoCapture.grab()) + { + VideoCapture.retrieve(Array); + cv::resize(Array, Array, cv::Size(1, 1)); + LightArray.Add(FColor(Array.data[2], Array.data[0], Array.data[1], 255)); + } + if (Array.empty()) + { + break; + } + } + VideoCapture.release(); + return LightArray; +} diff --git a/Source/Cut5/Utils/OpencvUtils.h b/Source/Cut5/Utils/OpencvUtils.h index 3da92b6..182539f 100644 --- a/Source/Cut5/Utils/OpencvUtils.h +++ b/Source/Cut5/Utils/OpencvUtils.h @@ -7,5 +7,6 @@ class FOpencvUtils public: static int32 GetVideoFrameCount(FString VideoPath); static TArray> GetVideoFrameLightArray(FString VideoPath, int32 X, int32 Y); + static TArray GetVideoSingleLightColor(FString VideoPath); }; diff --git a/Source/Cut5/Widgets/DefineGlobal.h b/Source/Cut5/Widgets/DefineGlobal.h index ccaa2a8..96876fd 100644 --- a/Source/Cut5/Widgets/DefineGlobal.h +++ b/Source/Cut5/Widgets/DefineGlobal.h @@ -94,6 +94,10 @@ struct CUT5_API FClipData TArray> LightArrayData; + // Player + FString PlayerName; + TArray PlayerLightData; + }; struct CUT5_API FTimelinePropertyData diff --git a/Source/Cut5/Widgets/MicroWidgets/SClickEditableText.cpp b/Source/Cut5/Widgets/MicroWidgets/SClickEditableText.cpp new file mode 100644 index 0000000..8f6b4eb --- /dev/null +++ b/Source/Cut5/Widgets/MicroWidgets/SClickEditableText.cpp @@ -0,0 +1,79 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "SClickEditableText.h" + +#include + +#include "SlateOptMacros.h" +#include "Widgets/Input/SEditableText.h" + +BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION + +void SClickEditableText::Construct(const FArguments& InArgs) +{ + TextPtr = InArgs._InitTextPtr; + OnEdited = InArgs._OnEdited; + ChildSlot + [ + SNew(SVerticalBox) + + SVerticalBox::Slot() + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) + [ + SAssignNew(Overlay, SOverlay) + + SOverlay::Slot() + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) + [ + SNew(SBorder) + .OnMouseDoubleClick_Lambda([this](const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) + { + CreateEditableBox(); + return FReply::Handled(); + }) + ] + + SOverlay::Slot() + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + [ + SAssignNew(TextBlock, STextBlock) + .Visibility(EVisibility::HitTestInvisible) + .Justification(ETextJustify::Center) + .Text(FText::FromString(*TextPtr)) + ] + ] + ]; + +} + +void SClickEditableText::CreateEditableBox() +{ + TextBlock->SetText(FText()); + EditableText = SNew(SEditableText) + .OnTextCommitted_Lambda([this](const FText& InText, ETextCommit::Type InCommitType) + { + FString Text = InText.ToString(); + if (Text.IsEmpty()) + { + TextBlock->SetText(FText::FromString(*TextPtr)); + return; + } + TextBlock->SetText(FText::FromString(FUtils::MakeStringUpright(InText.ToString()))); + Overlay->RemoveSlot(EditableText.ToSharedRef()); + if (!OnEdited.ExecuteIfBound(InText.ToString(), *TextPtr)) + { + check(false) + }; + *TextPtr = InText.ToString(); + + }); + Overlay->AddSlot() + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) + [ + EditableText.ToSharedRef() + ]; +} + +END_SLATE_FUNCTION_BUILD_OPTIMIZATION diff --git a/Source/Cut5/Widgets/MicroWidgets/SClickEditableText.h b/Source/Cut5/Widgets/MicroWidgets/SClickEditableText.h new file mode 100644 index 0000000..d9fcd83 --- /dev/null +++ b/Source/Cut5/Widgets/MicroWidgets/SClickEditableText.h @@ -0,0 +1,33 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Widgets/SCompoundWidget.h" +#include "Widgets/Input/SEditableText.h" + +/** + * + */ +class CUT5_API SClickEditableText : public SCompoundWidget +{ +public: + DECLARE_DELEGATE_TwoParams(FOnEdited, FString, FString) + SLATE_BEGIN_ARGS(SClickEditableText) + { + } + SLATE_ARGUMENT(FString*, InitTextPtr) + SLATE_EVENT(FOnEdited, OnEdited) + SLATE_END_ARGS() + + /** Constructs this widget with InArgs */ + void Construct(const FArguments& InArgs); + + TSharedPtr TextBlock; + TSharedPtr Overlay; + TSharedPtr EditableText; + FOnEdited OnEdited; + + FString* TextPtr; + void CreateEditableBox(); +}; diff --git a/Source/Cut5/Widgets/SCutMainWindow.cpp b/Source/Cut5/Widgets/SCutMainWindow.cpp index 1ef28cf..e0f710f 100644 --- a/Source/Cut5/Widgets/SCutMainWindow.cpp +++ b/Source/Cut5/Widgets/SCutMainWindow.cpp @@ -7,7 +7,10 @@ #include "SCustomInputPanel.h" #include "SCutTimeline.h" #include "SlateOptMacros.h" +#include "SPlayerLight.h" #include "STimelinePropertyPanel.h" +#include "STrackBody.h" +#include "STrackHead.h" #include "Widgets/Layout/SConstraintCanvas.h" #include "Widgets/Layout/SScaleBox.h" #include "Widgets/Views/STreeView.h" @@ -74,9 +77,17 @@ void SCutMainWindow::Construct(const FArguments& InArgs) [ SNew(SVerticalBox) + SVerticalBox::Slot() + [ + SAssignNew(PlayerGroupsPanel1, SHorizontalBox) + ] + + SVerticalBox::Slot() [ LightArrayPanel.ToSharedRef() ] + + SVerticalBox::Slot() + [ + SAssignNew(PlayerGroupsPanel2, SHorizontalBox) + ] ] + SHorizontalBox::Slot() .HAlign(HAlign_Fill) @@ -103,6 +114,28 @@ void SCutMainWindow::Construct(const FArguments& InArgs) } +void SCutMainWindow::Render() +{ + PlayerGroupsPanel1->ClearChildren(); + PlayerGroupsPanel2->ClearChildren(); + PlayerLightsSlateInstances.Empty(); + bool bSingle = false; + for (FSingleTrackGroupInstance& TrackGroupInstance : CutTimeline->TrackGroupInstances) + { + if (StaticCastSharedPtr(TrackGroupInstance.Head)->TrackData.TrackType == ETrackType::PlayerTrack) + { + TSharedPtr PlayerLight = SNew(SPlayerLight).Name(TrackGroupInstance.GroupName); + (bSingle ? PlayerGroupsPanel1 : PlayerGroupsPanel2)->AddSlot() + [ + PlayerLight.ToSharedRef() + ]; + bSingle = !bSingle; + PlayerLightsSlateInstances.Add(PlayerLight); + } + } + +} + FReply SCutMainWindow::OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) { const FTrackClipDragOperation& ClipDragOperation = static_cast(DragDropEvent.GetOperation().ToSharedRef().Get()); @@ -142,5 +175,49 @@ void SCutMainWindow::OnUpdateLightArray(const TArray& LightArray) LightArrayPanel->LightGridColors = LightArray; } +void SCutMainWindow::OnUpdatePlayers(TSharedPtr TrackBody, FColor PlayerColor) +{ + ICutMainWidgetInterface::OnUpdatePlayers(TrackBody, PlayerColor); + + for (int32 i = 0; i < PlayerLightsSlateInstances.Num(); i++) + { + const FString PlayerLightName = StaticCastSharedPtr(TrackBody)->TrackHead->TrackData.TrackName; + if (PlayerLightName == TEXT("玩家")) + { + PlayerLightsSlateInstances[i]->SetColor(PlayerColor); + break; + } + } +} + +void SCutMainWindow::OnAddNewTrack(ETrackType Type) +{ + ICutMainWidgetInterface::OnAddNewTrack(Type); + switch (Type) + { + case ETrackType::PlayerTrack: + { + Render(); + } + break; + default: + break; + } +} + +FString SCutMainWindow::GetGroupName(TSharedPtr WidgetInterface) +{ + for (FSingleTrackGroupInstance& Instance : CutTimeline->TrackGroupInstances) + { + if (Instance.IsThis(WidgetInterface)) + { + return Instance.GroupName; + } + } + return ""; + + +} + END_SLATE_FUNCTION_BUILD_OPTIMIZATION diff --git a/Source/Cut5/Widgets/SCutMainWindow.h b/Source/Cut5/Widgets/SCutMainWindow.h index a8dc331..d2b0ccf 100644 --- a/Source/Cut5/Widgets/SCutMainWindow.h +++ b/Source/Cut5/Widgets/SCutMainWindow.h @@ -6,6 +6,7 @@ #include "SCurtainPanel.h" #include "SCutTimeline.h" #include "SLightArrayPanel.h" +#include "SPlayerLight.h" #include "SVideoPlayer.h" #include "Cut5/Interface/CutMainWidgetInterface.h" #include "Widgets/SCompoundWidget.h" @@ -29,12 +30,20 @@ public: TSharedPtr LightArrayPanel; TSharedPtr VideoPlayer; TSharedPtr CurtainPanel; + TSharedPtr PlayerGroupsPanel1; + TSharedPtr PlayerGroupsPanel2; + + TArray> PlayerLightsSlateInstances; + + void Render(); virtual FReply OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override; virtual FReply OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override; - + virtual void OnUpdateVideo(FGuid UUID, UTexture2D* Texture) override; virtual void OnUpdateLightArray(const TArray& LightArray) override; - + virtual void OnUpdatePlayers(TSharedPtr TrackBody, FColor PlayerColor) override; + virtual void OnAddNewTrack(ETrackType Type) override; + virtual FString GetGroupName(TSharedPtr WidgetInterface) override; }; diff --git a/Source/Cut5/Widgets/SCutTimeline.cpp b/Source/Cut5/Widgets/SCutTimeline.cpp index 6536fa4..9503f6f 100644 --- a/Source/Cut5/Widgets/SCutTimeline.cpp +++ b/Source/Cut5/Widgets/SCutTimeline.cpp @@ -7,6 +7,7 @@ #include "STimelineTick.h" #include "STrackBody.h" #include "Cut5/Utils/Utils.h" +#include "MicroWidgets/SClickEditableText.h" #include "Widgets/Input/SButton.h" #include "Widgets/Input/SSlider.h" #include "Widgets/Layout/SScrollBox.h" @@ -244,12 +245,25 @@ void SCutTimeline::Tick(const FGeometry& AllottedGeometry, const double InCurren } } -TSharedPtr FSingleTrackGroupInstance::GetHead() +bool FSingleTrackGroupInstance::IsThis(TSharedPtr WidgetInterface) const +{ + if (StaticCastSharedPtr(WidgetInterface)) + { + return true; + } + else if (StaticCastSharedPtr(WidgetInterface)) + { + return true; + } + return false; +} + +TSharedPtr FSingleTrackGroupInstance::GetHead() const { return StaticCastSharedPtr(Head); } -TSharedPtr FSingleTrackGroupInstance::GetBody() +TSharedPtr FSingleTrackGroupInstance::GetBody() const { return StaticCastSharedPtr(Body); } @@ -282,6 +296,8 @@ void SCutTimeline::AddNewTrackToGroup(FString GroupName, FTrackData TrackData) } AddNewTrack(TrackData, 0, GroupName); RenderGroup(); + MainWidgetInterface->OnAddNewTrack(TrackData.TrackType); + } void SCutTimeline::SetAutoPlay(bool bStart) @@ -289,6 +305,26 @@ void SCutTimeline::SetAutoPlay(bool bStart) AutoPlaying = bStart; } +void SCutTimeline::OnGroupNameEdited(FString NewText, FString OldText) +{ + for (FSingleTrackGroupInstance& SingleTrackGroupInstance : TrackGroupInstances) + { + if (SingleTrackGroupInstance.GroupName == OldText) + { + SingleTrackGroupInstance.GroupName = NewText; + if (TSharedPtr Head = StaticCastSharedPtr(SingleTrackGroupInstance.Head)) + { + if (Head->TrackData.TrackType == ETrackType::PlayerTrack) + { + + Head->TrackData.TrackName = NewText; + + } + } + } + } +} + void SCutTimeline::RenderGroup() { TrackGroupScrollBox->ClearChildren(); @@ -305,9 +341,8 @@ void SCutTimeline::RenderGroup() .VAlign(VAlign_Fill) .HeightOverride(FGlobalData::DefaultTrackHeight * TrackGroups[i].TrackDataArray.Num()) [ - SNew(STextBlock) - .Text(FText::FromString(FUtils::MakeStringUpright(TrackGroups[i].GroupName))) - .Justification(ETextJustify::Center) + SNew(SClickEditableText).InitTextPtr(&TrackGroups[i].GroupName) + .OnEdited_Raw(this, &SCutTimeline::OnGroupNameEdited) ] ]; diff --git a/Source/Cut5/Widgets/SCutTimeline.h b/Source/Cut5/Widgets/SCutTimeline.h index bf7e7a5..a35e48b 100644 --- a/Source/Cut5/Widgets/SCutTimeline.h +++ b/Source/Cut5/Widgets/SCutTimeline.h @@ -28,14 +28,15 @@ struct FTrackGroup struct FSingleTrackGroupInstance { - FSingleTrackGroupInstance(const TSharedPtr Head, const TSharedPtr Body, const FString& GroupName) + FSingleTrackGroupInstance(const TSharedPtr Head, const TSharedPtr Body, FString GroupName) { this->Head = Head; this->Body = Body; this->GroupName = GroupName; } - TSharedPtr GetHead(); - TSharedPtr GetBody(); + bool IsThis(TSharedPtr WidgetInterface) const; + TSharedPtr GetHead() const; + TSharedPtr GetBody() const; FString GroupName; TSharedPtr Head; TSharedPtr Body; @@ -62,6 +63,7 @@ public: void SetAutoPlay(bool bStart); bool AutoPlaying = false; + void OnGroupNameEdited(FString NewText, FString OldText); void RenderGroup(); ICutMainWidgetInterface* MainWidgetInterface; diff --git a/Source/Cut5/Widgets/SLightArrayPanel.cpp b/Source/Cut5/Widgets/SLightArrayPanel.cpp index 43855d8..95f4b2f 100644 --- a/Source/Cut5/Widgets/SLightArrayPanel.cpp +++ b/Source/Cut5/Widgets/SLightArrayPanel.cpp @@ -19,8 +19,7 @@ void SLightArrayPanel::Construct(const FArguments& InArgs) SNew(SScaleBox) [ SNew(SBox) - .WidthOverride(600) - .HeightOverride(480) + .HAlign(HAlign_Fill) .VAlign(VAlign_Fill) [ @@ -65,6 +64,7 @@ int32 SLightArrayPanel::OnPaint(const FPaintArgs& Args, const FGeometry& Allotte const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { + for (int32 i = 0; i < FGlobalData::LightArrayX; i++) { for (int32 j = 0; j < FGlobalData::LightArrayY; j++) @@ -73,10 +73,10 @@ int32 SLightArrayPanel::OnPaint(const FPaintArgs& Args, const FGeometry& Allotte FSlateDrawElement::MakeBox( OutDrawElements, LayerId, - AllottedGeometry.ToPaintGeometry(FVector2D(600.0 / FGlobalData::LightArrayX - 1.2, 400.0 / FGlobalData::LightArrayY - 1.2), FSlateLayoutTransform(FVector2D(i * 600.0 / FGlobalData::LightArrayX, j * 400.0 / FGlobalData::LightArrayY))), + AllottedGeometry.ToPaintGeometry(FVector2D(GetCachedGeometry().GetLocalSize().X / FGlobalData::LightArrayX - 1.2, GetCachedGeometry().GetLocalSize().X * 0.6666 / FGlobalData::LightArrayY - 1.2), FSlateLayoutTransform(FVector2D(i * GetCachedGeometry().GetLocalSize().X / FGlobalData::LightArrayX, j * GetCachedGeometry().GetLocalSize().X * 0.6666 / FGlobalData::LightArrayY))), &Brush, ESlateDrawEffect::None, - LightGridColors[i * FGlobalData::LightArrayY + j]); + LightGridColors[j * FGlobalData::LightArrayX + i]); } } diff --git a/Source/Cut5/Widgets/SPlayerLight.cpp b/Source/Cut5/Widgets/SPlayerLight.cpp new file mode 100644 index 0000000..f611ed4 --- /dev/null +++ b/Source/Cut5/Widgets/SPlayerLight.cpp @@ -0,0 +1,32 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "SPlayerLight.h" + +#include "SlateOptMacros.h" +#include "Widgets/Layout/SScaleBox.h" + +BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION + +void SPlayerLight::Construct(const FArguments& InArgs) +{ + Name = InArgs._Name; + FSlateDynamicImageBrush* SlateDynamicImageBrush = new FSlateDynamicImageBrush(*(FPaths::ProjectDir() + "/Resources/" + "PlayerLight.png"), FVector2D(128, 128)); + + ChildSlot + [ + SNew(SScaleBox) + [ + SAssignNew(PlayerLightImage, SImage) + .Image(SlateDynamicImageBrush) + ] + ]; + +} + +void SPlayerLight::SetColor(FColor Color) +{ + PlayerLightImage->SetColorAndOpacity(FLinearColor(Color)); +} + +END_SLATE_FUNCTION_BUILD_OPTIMIZATION diff --git a/Source/Cut5/Widgets/SPlayerLight.h b/Source/Cut5/Widgets/SPlayerLight.h new file mode 100644 index 0000000..00401e8 --- /dev/null +++ b/Source/Cut5/Widgets/SPlayerLight.h @@ -0,0 +1,26 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Widgets/SCompoundWidget.h" + +/** + * + */ +class CUT5_API SPlayerLight : public SCompoundWidget +{ +public: + SLATE_BEGIN_ARGS(SPlayerLight) + { + } + SLATE_ARGUMENT(FString, Name) + SLATE_END_ARGS() + + /** Constructs this widget with InArgs */ + void Construct(const FArguments& InArgs); + + void SetColor(FColor Color); + TSharedPtr PlayerLightImage; + FString Name; +}; diff --git a/Source/Cut5/Widgets/STimelineClip.cpp b/Source/Cut5/Widgets/STimelineClip.cpp index 186405f..ce594d4 100644 --- a/Source/Cut5/Widgets/STimelineClip.cpp +++ b/Source/Cut5/Widgets/STimelineClip.cpp @@ -4,6 +4,7 @@ #include "STimelineClip.h" #include "SlateOptMacros.h" +#include "Cut5/WidgetInterface.h" #include "Engine/Engine.h" #include "Engine/Texture2D.h" @@ -37,6 +38,7 @@ void STimelineClip::Construct(const FArguments& InArgs) { ClipData = InArgs._InClipData; MainWidgetInterface = InArgs._MainWidgetInterface; + Body = InArgs._Body; SetRenderTransform(FSlateRenderTransform(FVector2D(FMath::TruncToInt(ClipData->ClipStartTime / FGlobalData::DefaultTimeTickSpace) * FGlobalData::DefaultTimeTickSpace, 0))); ChildSlot [ @@ -127,7 +129,17 @@ void STimelineClip::Seek(int32 Frame) } break; } - + case ETrackType::PlayerTrack: + { + const int32 Offset = Frame - (ClipData->ClipStartTime / FGlobalData::DefaultTimeTickSpace); + const int32 SeekMovieFrame = ClipData->VideoStartFrame + Offset; + if (SeekMovieFrame < ClipData->PlayerLightData.Num()) + { + MainWidgetInterface->OnUpdatePlayers(Body, ClipData->PlayerLightData[SeekMovieFrame]); + } + break; + } + break; default: break; } diff --git a/Source/Cut5/Widgets/STimelineClip.h b/Source/Cut5/Widgets/STimelineClip.h index 448eb9d..3b62861 100644 --- a/Source/Cut5/Widgets/STimelineClip.h +++ b/Source/Cut5/Widgets/STimelineClip.h @@ -24,6 +24,7 @@ public: } SLATE_ARGUMENT(FClipData*, InClipData) SLATE_ARGUMENT(ICutMainWidgetInterface*, MainWidgetInterface) + SLATE_ARGUMENT(TSharedPtr, Body) SLATE_END_ARGS() FReply OnBorderMouseButtonDown(const FGeometry& Geometry, const FPointerEvent& PointerEvent); @@ -36,7 +37,7 @@ public: void UpdatePosition(double StartTime); void UpdateLength(double X); virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; - + TSharedPtr Body; int32 LastSeekFrame = 0; }; diff --git a/Source/Cut5/Widgets/STimelineProperty.cpp b/Source/Cut5/Widgets/STimelineProperty.cpp index ce18b71..85d1ec7 100644 --- a/Source/Cut5/Widgets/STimelineProperty.cpp +++ b/Source/Cut5/Widgets/STimelineProperty.cpp @@ -14,8 +14,8 @@ void STimelineProperty::Construct(const FArguments& InArgs) ChildSlot [ SNew(SBox) - .WidthOverride(128) - .HeightOverride(128) + .WidthOverride(80) + .HeightOverride(80) .Padding(10, 10, 10, 10) [ SNew(SOverlay) diff --git a/Source/Cut5/Widgets/STimelinePropertyPanel.cpp b/Source/Cut5/Widgets/STimelinePropertyPanel.cpp index 3d19988..d25b87c 100644 --- a/Source/Cut5/Widgets/STimelinePropertyPanel.cpp +++ b/Source/Cut5/Widgets/STimelinePropertyPanel.cpp @@ -34,13 +34,21 @@ void STimelinePropertyPanel::Construct(const FArguments& InArgs) .Text(FText::FromString(TEXT("角色组"))) ] + SOverlay::Slot() - .HAlign(HAlign_Right) - .VAlign(VAlign_Bottom) + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) [ SNew(SButton) - .OnClicked_Lambda([]() + .OnClicked_Lambda([this]() { - + if (MainWindow->CutTimeline->TrackGroups.FindByPredicate([](const FTrackGroup& TrackGroup) + { + return TrackGroup.GroupName == TEXT("未命名"); + })) + { + return FReply::Handled(); + } + const FTrackData PlayerData(TEXT("玩家"), ETrackType::PlayerTrack); + MainWindow->CutTimeline->AddNewTrackToGroup(TEXT("未命名"), PlayerData); return FReply::Handled(); }) ] diff --git a/Source/Cut5/Widgets/STrackBody.cpp b/Source/Cut5/Widgets/STrackBody.cpp index 9dd8083..0e858e4 100644 --- a/Source/Cut5/Widgets/STrackBody.cpp +++ b/Source/Cut5/Widgets/STrackBody.cpp @@ -51,7 +51,7 @@ void STrackBody::CallRender() TrackHead->CutTimeline->UpdateTimelineLength(); } TSharedPtr TimelineClip; - TimelineClip = SNew(STimelineClip).InClipData(&TempClipData).MainWidgetInterface(MainWidgetInterface); + TimelineClip = SNew(STimelineClip).InClipData(&TempClipData).MainWidgetInterface(MainWidgetInterface).Body(SharedThis(this)); Overlay->AddSlot() .HAlign(HAlign_Left) @@ -75,7 +75,8 @@ FReply STrackBody::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& Dra const FTrackClipDragOperation& ClipDragOperation = static_cast(DragDropEvent.GetOperation().ToSharedRef().Get()); if (ClipDragOperation.TimelinePropertyData.Type != TrackHead->TrackData.TrackType) { - if (ClipDragOperation.TimelinePropertyData.Type == ETrackType::VideoTrack && TrackHead->TrackData.TrackType == ETrackType::LightArrayTrack) + if ((ClipDragOperation.TimelinePropertyData.Type == ETrackType::VideoTrack && TrackHead->TrackData.TrackType == ETrackType::LightArrayTrack) + || (ClipDragOperation.TimelinePropertyData.Type == ETrackType::VideoTrack && TrackHead->TrackData.TrackType == ETrackType::PlayerTrack)) { } else @@ -92,6 +93,7 @@ FReply STrackBody::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& Dra NewClipData.ClipColors.Add(FLinearColor(1, 1, 1, 1)); if (ClipDragOperation.TimelinePropertyData.Type == ETrackType::VideoTrack) { + // 如果拖拽物是视频,那么对不同轨道进行不同和操作 NewClipData.MoviePath = ClipDragOperation.TimelinePropertyData.MoviePath; NewClipData.ClipEndTime = NewClipData.ClipStartTime + ClipDragOperation.TimelinePropertyData.MovieFrameLength * FGlobalData::DefaultTimeTickSpace; NewClipData.VideoCapture = ClipDragOperation.VideoCapture; @@ -100,6 +102,12 @@ FReply STrackBody::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& Dra NewClipData.ClipType = ETrackType::LightArrayTrack; NewClipData.LightArrayData = FOpencvUtils::GetVideoFrameLightArray(ClipDragOperation.TimelinePropertyData.MoviePath, FGlobalData::LightArrayX, FGlobalData::LightArrayY); } + if (TrackHead->TrackData.TrackType == ETrackType::PlayerTrack) + { + NewClipData.ClipType = ETrackType::PlayerTrack; + NewClipData.PlayerName = MainWidgetInterface->GetGroupName(SharedThis(this)); + NewClipData.PlayerLightData = FOpencvUtils::GetVideoSingleLightColor(ClipDragOperation.TimelinePropertyData.MoviePath); + } } else if (ClipDragOperation.TimelinePropertyData.Type == ETrackType::LightArrayTrack) { diff --git a/Test.png b/Test.png new file mode 100644 index 0000000..b06c661 Binary files /dev/null and b/Test.png differ