diff --git a/Cut5.sln.DotSettings.user b/Cut5.sln.DotSettings.user index 82c3d3d..8c35d97 100644 --- a/Cut5.sln.DotSettings.user +++ b/Cut5.sln.DotSettings.user @@ -1,2 +1,3 @@  + SUGGESTION True \ No newline at end of file diff --git a/Source/Cut5/Interface/SoundInterface.cpp b/Source/Cut5/Interface/SoundInterface.cpp index 4e262a4..c81454b 100644 --- a/Source/Cut5/Interface/SoundInterface.cpp +++ b/Source/Cut5/Interface/SoundInterface.cpp @@ -44,7 +44,7 @@ uint32 FSoundThread::Run() { const int32 Offset = SeekedFrame * (SampleRate / FGlobalData::GlobalFPS) * ByteNum * 2; const int32 Size = SampleRate / FGlobalData::GlobalFPS; - if (Audio.Num() < Offset + Size) + if (Audio.Num() < Offset + Size * ByteNum) { SeekedFrame = 0; continue; diff --git a/Source/Cut5/Utils/Utils.cpp b/Source/Cut5/Utils/Utils.cpp index ab2c2c1..88b747c 100644 --- a/Source/Cut5/Utils/Utils.cpp +++ b/Source/Cut5/Utils/Utils.cpp @@ -589,8 +589,8 @@ TArray FUtils::ExportPsaf(FTrackData TrackData, const FString& - - FString psafPath = ExportPath + ExportName + FString::FromInt(i) + ".psaf"; + + FString psafPath = ExportPath + FString::FromInt(i) + ".psaf"; FString psafPath2 = leftStr + ".psaf2"; diff --git a/Source/Cut5/Widgets/Curtain/SCurtain.cpp b/Source/Cut5/Widgets/Curtain/SCurtain.cpp index 98bf1d0..f7a5544 100644 --- a/Source/Cut5/Widgets/Curtain/SCurtain.cpp +++ b/Source/Cut5/Widgets/Curtain/SCurtain.cpp @@ -47,7 +47,27 @@ void SCurtain::Construct(const FArguments& InArgs) .ButtonStyle(FCutButtonStyle::Get(), Curtain->bIsActive ? "Curtain.CurtainButtonSelected" : "Curtain.CurtainButton") .OnClicked_Lambda([this]() { - TSharedPtr CurtainDragDrop = OpenThis(); + TSharedPtr CurtainDragDrop; + if (!Curtain->bIsActive) + { + CurtainDragDrop = OpenThis(); + InlineEditableTextBlock->EnterEditingMode(); + } + else + { + InlineEditableTextBlock->EnterEditingMode(); + } + + if (CurtainDragDrop == nullptr) + { + CurtainDragDrop = MakeShared(); + CurtainDragDrop->CurtainIndex = CurtainIndex; + CurtainDragDrop->GroupIndex = CurtainGroup - &CurtainPanel->Groups[0]; + CurtainDragDrop->DragDropType = FCutDragDropBase::EType::CurtainDrag; + CurtainDragDrop->DraggingWidget = SharedThis(this); + + } + return FReply::Handled().DetectDrag(SharedThis(this), EKeys::LeftMouseButton).BeginDragDrop(CurtainDragDrop.ToSharedRef()); }) ] @@ -66,6 +86,13 @@ void SCurtain::Construct(const FArguments& InArgs) + SHorizontalBox::Slot() [ SAssignNew(InlineEditableTextBlock, SInlineEditableTextBlock) + .OnEnterEditingMode_Lambda([this]() + { + if (!Curtain->bIsActive) + { + OpenThis(); + } + }) .Text(FText::FromString(Curtain->CurtainName)) .Font(TitleText.Font) .OnTextCommitted_Lambda([this](const FText& Text, ETextCommit::Type CommitType) @@ -114,10 +141,11 @@ FReply SCurtain::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEv CurtainPanel->ShowCurtainCommand(Curtain->CurtainUUID); return FReply::Handled(); } - if (!Curtain->bIsActive) - { - OpenThis(); - } + InlineEditableTextBlock->EnterEditingMode(); + // if (!Curtain->bIsActive) + // { + // OpenThis(); + // } return SCompoundWidget::OnMouseButtonDown(MyGeometry, MouseEvent); } diff --git a/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp b/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp index 5212bd7..0149293 100644 --- a/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp +++ b/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp @@ -418,9 +418,7 @@ void SEffectCardGroup::CallRender() .VAlign(VAlign_Fill) .OnClicked_Lambda([this]() { - // 新建卡牌后 对卡牌进行个体保存。 - FEffectCardProperty NewCard; - NewCard.Name = TEXT("未命名") + NewCard.Guid.ToString(); + @@ -437,6 +435,10 @@ void SEffectCardGroup::CallRender() } ID++; } + + // 新建卡牌后 对卡牌进行个体保存。 + FEffectCardProperty NewCard; + NewCard.Name = TEXT("未命名") + FString::FromInt(ID); NewCard.ID = ID; diff --git a/Source/Cut5/Widgets/MicroWidgets/SNewProjectTips.cpp b/Source/Cut5/Widgets/MicroWidgets/SNewProjectTips.cpp index 831902a..31f56fb 100644 --- a/Source/Cut5/Widgets/MicroWidgets/SNewProjectTips.cpp +++ b/Source/Cut5/Widgets/MicroWidgets/SNewProjectTips.cpp @@ -11,6 +11,7 @@ BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION void SNewProjectTips::Construct(const FArguments& InArgs) { OnEnsure = InArgs._OnEnsure; + AlreadyExistsData = InArgs._AlreadyExistsData; FTextBlockStyle NormalText = FAppStyle::GetWidgetStyle("NormalText"); NormalText.SetFontSize(20); ChildSlot @@ -58,6 +59,12 @@ void SNewProjectTips::Construct(const FArguments& InArgs) ConfirmButton->SetEnabled(false); return false; } + if (AlreadyExistsData.Contains(InText.ToString())) + { + OutText = FText::FromString(TEXT("项目名称已存在")); + ConfirmButton->SetEnabled(false); + return false; + } ConfirmButton->SetEnabled(true); return true; }) @@ -68,7 +75,7 @@ void SNewProjectTips::Construct(const FArguments& InArgs) { if (OnEnsure.ExecuteIfBound(InText.ToString())) { - + } } diff --git a/Source/Cut5/Widgets/MicroWidgets/SNewProjectTips.h b/Source/Cut5/Widgets/MicroWidgets/SNewProjectTips.h index e818887..364feed 100644 --- a/Source/Cut5/Widgets/MicroWidgets/SNewProjectTips.h +++ b/Source/Cut5/Widgets/MicroWidgets/SNewProjectTips.h @@ -17,6 +17,7 @@ public: { } SLATE_ARGUMENT(FString, Title) + SLATE_ARGUMENT(TArray, AlreadyExistsData) SLATE_ARGUMENT(FString, SubTitle) SLATE_EVENT(FOnEnsure, OnEnsure) SLATE_END_ARGS() @@ -26,5 +27,7 @@ public: TSharedPtr EditableTextBox; TSharedPtr ConfirmButton; + + TArray AlreadyExistsData; FOnEnsure OnEnsure; }; diff --git a/Source/Cut5/Widgets/SCutMainWindow.cpp b/Source/Cut5/Widgets/SCutMainWindow.cpp index bc8b3e8..d4809d3 100644 --- a/Source/Cut5/Widgets/SCutMainWindow.cpp +++ b/Source/Cut5/Widgets/SCutMainWindow.cpp @@ -121,6 +121,13 @@ void SCutMainWindow::Construct(const FArguments& InArgs) ] ] + SHorizontalBox::Slot() + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(FText::FromString(FString::Printf(TEXT("Ver. %s"), *FGlobalData::CutVersion))) + .Justification(ETextJustify::Center) + ] + + SHorizontalBox::Slot() .SizeParam(FStretch(1.0)) [ SNew(SSpacer) @@ -493,29 +500,43 @@ void SCutMainWindow::Construct(const FArguments& InArgs) CutTimeline->CopyClipData.Empty(); TArray ClipBoardData; FMemoryWriter Archive(ClipBoardData); - int32 Count = CutTimeline->SelectedClips.Num(); - TArray SavedData; + + // first nest is the number of track group instances + // second nest is the number of clips in each track group instance + // nest can be empty + TArray> SavedData; + + + + int32 i = 0; + bool bHasData = false; for (FSingleTrackGroupInstance& Instance : CutTimeline->TrackGroupInstances) { - TSharedPtr TrackBody = StaticCastSharedPtr(Instance.Body); + TArray TempSavedData; + const TSharedPtr TrackBody = StaticCastSharedPtr(Instance.Body); for (FClipData& ClipData : TrackBody->TrackHead->TrackData.ClipData) { if (CutTimeline->SelectedClips.Contains(ClipData.ClipGuid)) { - SavedData.Add(ClipData); - break; + bHasData = true; + TempSavedData.Add(ClipData); + continue; } - + } + if (bHasData) + { + i++; + SavedData.Add(TempSavedData); } } Archive << SavedData; - - FString Base = FBase64::Encode(ClipBoardData); + + const FString Base = FBase64::Encode(ClipBoardData); FPlatformApplicationMisc::ClipboardCopy(*Base); })); CommandList->MapAction(FShortCutCommands::Get().Paste, FExecuteAction::CreateLambda([this]() { - + UpdateProperties(nullptr); FString ClipBoardString; FPlatformApplicationMisc::ClipboardPaste(ClipBoardString); TArray Dest; @@ -524,27 +545,64 @@ void SCutMainWindow::Construct(const FArguments& InArgs) FMemoryReader Reader(Dest); - TArray CopyClipData; + TArray> CopyClipData; Reader << CopyClipData; - // for (FClipData& ClipData : CopyClipData) - // { - // for (FSingleTrackGroupInstance& Instance : CutTimeline->TrackGroupInstances) - // { - // TSharedPtr TrackBody = StaticCastSharedPtr(Instance.Body); - // FVector2D Pos = TrackBody->GetCachedGeometry().AbsoluteToLocal(NewMouseEvent.GetScreenSpacePosition()); - // if (TrackBody->TrackHead->TrackData.DeviceTrack.Guid == ClipData.BindTrackGuid) - // { - // FClipData NewClipData = ClipData; - // NewClipData.ClipGuid = FGuid::NewGuid(); - // int32 Length = NewClipData.ClipEndFrame - NewClipData.ClipStartFrame; - // NewClipData.ClipStartFrame = FMath::RoundToInt(Pos.X / FGlobalData::DefaultTimeTickSpace); - // NewClipData.ClipEndFrame = NewClipData.ClipStartFrame + Length; - // DragDropOperator::GetDragDropOperator()->UpdateClipProcess(this, NewClipData); - // TrackBody->TrackHead->TrackData.ClipData.Add(NewClipData); - // TrackBody->CallRender(); - // } - // } - // } + + // 先计算出最靠左侧的片段 + int32 MostLeftFrame = INT_MAX; + for (TArray& ClipDataArray : CopyClipData) + { + for (const FClipData& ClipData : ClipDataArray) + { + MostLeftFrame = FMath::Min(MostLeftFrame, ClipData.ClipStartFrame); + } + } + + + int32 CurrentIndex = 0; + TSharedPtr BeginBody = CutTimeline->GetCurrentCursorUsingBody(); + for (TArray& ClipDataArray : CopyClipData) + { + if (ClipDataArray.Num() == 0) + { + BeginBody = CutTimeline->IterateTrackBody(BeginBody); + CurrentIndex++; + continue; + } + if (BeginBody == nullptr) + { + // IterateTrackBody will return nullptr if the track body is the last one + break; + } + + + for (FClipData& ClipData : ClipDataArray) + { + if (FUtils::DetectDragTypeCanDrop(ClipData, BeginBody->TrackHead->TrackData.TrackType)) + { + FVector2D Pos = BeginBody->GetCachedGeometry().AbsoluteToLocal(NewMouseEvent.GetScreenSpacePosition()); + FClipData NewClipData = ClipData; + NewClipData.ClipGuid = FGuid::NewGuid(); + NewClipData.BindTrackGuid = BeginBody->TrackHead->TrackData.DeviceTrack.Guid; + + int32 Offset = NewClipData.ClipStartFrame - MostLeftFrame; + + int32 Length = NewClipData.ClipEndFrame - NewClipData.ClipStartFrame; + NewClipData.ClipStartFrame = FMath::RoundToInt(Pos.X / FGlobalData::DefaultTimeTickSpace) + Offset; + NewClipData.ClipEndFrame = NewClipData.ClipStartFrame + Length; + + + + + BeginBody->TrackHead->TrackData.ClipData.Add(NewClipData); + DragDropOperator::GetDragDropOperator()->UpdateClipProcess(this, NewClipData); + } + } + + BeginBody->CallRender(); + BeginBody = CutTimeline->IterateTrackBody(BeginBody); + CurrentIndex++; + } })); FMainMenuCommands::Register(); @@ -993,9 +1051,11 @@ void SCutMainWindow::ExportProject(const FString& ExportPath) FGlobalData::ExportPath = ExportPath / FGlobalData::CurrentProjectName + TEXT("_XML"); FPlatformFileManager::Get().GetPlatformFile().DeleteDirectoryRecursively(*FGlobalData::ExportPath); + IDList.Empty(); FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*FGlobalData::ExportPath); + FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(TEXT("C://temp")); FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*(FGlobalData::ExportPath / "Video")); FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*(FGlobalData::ExportPath / "Sound")); FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*(FGlobalData::ExportPath / "PSAF")); @@ -1151,7 +1211,7 @@ 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].Cards[j].ID))); + 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))); } } @@ -1261,10 +1321,7 @@ void SCutMainWindow::ImportProject(const FString& ImportPath) void SCutMainWindow::NewProject(const FString& NewPath) { - FUtils::AddTips(SNew(STips).Title(TEXT("警告")).SubTitle(TEXT("目录不为空!")).OnEnsure_Lambda([](const FString& String) - { - - })); + FGlobalData::BasePath = NewPath; CutTimeline->TimelineInfo.CurrentOpenFullPath = FUtils::MainSaveFullPath(); @@ -1332,15 +1389,43 @@ bool SCutMainWindow::PreNewProject() IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); DesktopPlatform->OpenDirectoryDialog(nullptr, TEXT("选择新建路径"), String, String); if (String.IsEmpty()) + { return false; - FGlobalData::BasePath = String; + } + + // 检测目录是否为空 + + + + + + + class FDirectoryVisitor : public IPlatformFile::FDirectoryVisitor + { + virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) override + { + if (bIsDirectory) + { + Directories.Add(FilenameOrDirectory); + } + return true; + }; + public: + TArray Directories; + }; + FDirectoryVisitor Visitor; + FPlatformFileManager::Get().GetPlatformFile().IterateDirectory(*String, Visitor); + TSharedPtr NewProjectTips = SNew(SNewProjectTips) + .AlreadyExistsData(Visitor.Directories) .Title(TEXT("新建项目名字")); - NewProjectTips->OnEnsure.BindLambda([this, NewProjectTips](FString String) + + NewProjectTips->OnEnsure.BindLambda([this, NewProjectTips, String](FString EnsureString) { - FGlobalData::CurrentProjectName = String; + FGlobalData::BasePath = String; + FGlobalData::CurrentProjectName = EnsureString; GEngine->GameViewport->RemoveViewportWidgetContent(NewProjectTips.ToSharedRef()); }); GEngine->GameViewport->AddViewportWidgetContent( @@ -1864,8 +1949,21 @@ tinyxml2::XMLElement* SCutMainWindow::GetVideoElement(tinyxml2::XMLElement* Pare VolumeEventValue->InsertNewText("100"); } } + Index++; + } + + + if (Index == 0) + { + tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent"); + { + tinyxml2::XMLElement* VolumeEventTimeCode = VolumeEvent->InsertNewChildElement("TimeCode"); + tinyxml2::XMLElement* VolumeEventValue = VolumeEvent->InsertNewChildElement("Value"); + + VolumeEventTimeCode->InsertNewText("0"); + VolumeEventValue->InsertNewText("100"); + } } - Index++; } else { @@ -2066,6 +2164,18 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundElement(tinyxml2::XMLElement* Pare Index++; } + + if (Index == 0) + { + tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent"); + { + tinyxml2::XMLElement* VolumeEventTimeCode = VolumeEvent->InsertNewChildElement("TimeCode"); + tinyxml2::XMLElement* VolumeEventValue = VolumeEvent->InsertNewChildElement("Value"); + + VolumeEventTimeCode->InsertNewText("0"); + VolumeEventValue->InsertNewText("100"); + } + } } else diff --git a/Source/Cut5/Widgets/SCutTimeline.cpp b/Source/Cut5/Widgets/SCutTimeline.cpp index bbd4f4a..588885e 100644 --- a/Source/Cut5/Widgets/SCutTimeline.cpp +++ b/Source/Cut5/Widgets/SCutTimeline.cpp @@ -320,7 +320,7 @@ void SCutTimeline::Construct(const FArguments& InArgs) [ // Track Body SAssignNew(TrackBodyScrollBox, SScrollBox) - + .AllowOverscroll(EAllowOverscroll::Yes) .ScrollBarVisibility(EVisibility::Hidden) .AnimateWheelScrolling(true) .OnUserScrolled_Lambda([this](float ScrollValue) @@ -841,6 +841,44 @@ TArray SCutTimeline::GetClipDataByType(ETrackType TrackType) return ClipData; } +TSharedPtr SCutTimeline::GetCurrentCursorUsingBody() +{ + float Y = TrackBodyScrollBox->GetCachedGeometry().AbsoluteToLocal(FSlateApplication::Get().GetCursorPos()).Y + TrackBodyScrollBox->GetScrollOffset(); + int32 i = 0; + for (FSingleTrackGroupInstance& TrackGroup : TrackGroupInstances) + { + float CurrentY = FGlobalData::DefaultTrackHeight * i; + TSharedPtr TrackBody = StaticCastSharedPtr(TrackGroup.Body); + if (Y >= CurrentY && Y <= CurrentY + TrackBody->GetCachedGeometry().GetLocalSize().Y) + { + return TrackBody; + } + i++; + } + return nullptr; +} + +TSharedPtr SCutTimeline::IterateTrackBody(TSharedPtr CurrentBody) +{ + int32 i = 0; + for (FSingleTrackGroupInstance& TrackGroup : TrackGroupInstances) + { + if (TrackGroup.Body == CurrentBody) + { + if (i + 1 < TrackGroupInstances.Num()) + { + return StaticCastSharedPtr(TrackGroupInstances[i + 1].Body); + } + else + { + return nullptr; + } + } + i++; + } + return nullptr; +} + FReply SCutTimeline::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) { diff --git a/Source/Cut5/Widgets/SCutTimeline.h b/Source/Cut5/Widgets/SCutTimeline.h index ed4f947..538f695 100644 --- a/Source/Cut5/Widgets/SCutTimeline.h +++ b/Source/Cut5/Widgets/SCutTimeline.h @@ -107,6 +107,8 @@ public: FTrackGroup* GetTrackGroupByName(FString GroupName); FTrackData* GetTrackDataByType(ETrackType TrackType); TArray GetClipDataByType(ETrackType TrackType); + TSharedPtr GetCurrentCursorUsingBody(); + TSharedPtr IterateTrackBody(TSharedPtr CurrentBody); ICutMainWidgetInterface* MainWidgetInterface; diff --git a/Source/Cut5/Widgets/STimelineClip.cpp b/Source/Cut5/Widgets/STimelineClip.cpp index 1e30b57..330ce88 100644 --- a/Source/Cut5/Widgets/STimelineClip.cpp +++ b/Source/Cut5/Widgets/STimelineClip.cpp @@ -320,6 +320,10 @@ void STimelineClip::Seek(int32 Frame) { MainWidgetInterface->OnUpdateProjector(0, false); } + else + { + MainWidgetInterface->OnUpdateProjector(0, true); + } break; } case ETrackType::VideoTrack: @@ -668,11 +672,11 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe } if (ClipData->bIsCycle == true) { - 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->bIsVirtual == true) { - 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); }