特效面板雏形

This commit is contained in:
Sch 2023-07-20 21:02:20 +08:00
parent 53184d30d2
commit 0693f268e6
16 changed files with 521 additions and 9 deletions

BIN
Resources/EffectCard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 B

View File

@ -31,7 +31,8 @@ public:
virtual void OnAddNewTrack(ETrackType Type) {};
virtual void OnRemoveTrack(FGuid UUID) {};
virtual void OnUpdateSound(uint8* Data, int32 Size) {};
virtual void AddNewCard(FEffectCardProperty& CardProperty, FString GroupName) {};
virtual FString GetGroupName(TSharedPtr<class IWidgetInterface> WidgetInterface) { return FString(); };
virtual FTimelinePropertyData* GetResourcePropertyDataPtr(FGuid GUID) { return nullptr; };

View File

@ -50,3 +50,15 @@ uint8* FUtils::ConvertTwoChannelSound2PortAudioSound(uint8* Channel1, uint8* Cha
return static_cast<uint8*>(Data);
}
FString FUtils::GetResourcesPath(FString ResourcesName)
{
return FPaths::Combine(FPaths::ProjectDir() + "/Resources/", ResourcesName);
}
FSlateDynamicImageBrush* FUtils::GetBrushFromImage(const FString& ImageName, const FVector2D Size)
{
FSlateDynamicImageBrush* Brush = new FSlateDynamicImageBrush(*ImageName, Size);
return Brush;
}

View File

@ -9,4 +9,8 @@ public:
// Size is nb_samples if it was float type
static uint8* ConvertFfMpegSound2PortAudioSound(uint8* inData[8], int32 Size);
static uint8* ConvertTwoChannelSound2PortAudioSound(uint8* Channel1, uint8* Channel2, int32 Size);
static FString GetResourcesPath(FString ResourcesName);
static FSlateDynamicImageBrush* GetBrushFromImage(const FString& ImageName, const FVector2D Size);
static TArray<FSlateDynamicImageBrush*> BrushPtr;
};

View File

@ -21,6 +21,7 @@ public:
inline static int32 LightArrayY = 42;
inline static float CurrentTimeScroll = 0.0f;
inline static float GlobalFPS = 30.0f;
inline static FString CurrentProjectName = "DefaultProject";
static int32 GetAlignOfTickSpace(double Align, bool bCeil = false)
{
return bCeil ? FMath::CeilToInt(Align / FGlobalData::DefaultTimeTickSpace) * FGlobalData::DefaultTimeTickSpace :
@ -215,3 +216,34 @@ public:
EDragType DragType;
};
struct CUT5_API FEffectCardProperty
{
FEffectCardProperty() {};
FGuid Guid = FGuid::NewGuid();
FString Name = "";
FString TimelineBinaryPath = "";
friend FArchive& operator<<(FArchive& Ar, FEffectCardProperty& EffectCardProperty)
{
Ar << EffectCardProperty.Guid;
Ar << EffectCardProperty.Name;
Ar << EffectCardProperty.TimelineBinaryPath;
return Ar;
};
};
struct CUT5_API FEffectCardGroup
{
FString GroupName;
TArray<FEffectCardProperty> Cards;
bool bIsDedicated = false;
friend FArchive& operator<<(FArchive& Ar, FEffectCardGroup& EffectCard)
{
Ar << EffectCard.GroupName;
Ar << EffectCard.Cards;
Ar << EffectCard.bIsDedicated;
return Ar;
};
};

View File

@ -0,0 +1,51 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "SEffectCard.h"
#include "SlateOptMacros.h"
#include "Cut5/Utils/Utils.h"
#include "Cut5/Widgets/MicroWidgets/SClickEditableText.h"
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SEffectCard::OnNameEdited(FString New, FString Old)
{
CardProperty->Name = New;
}
void SEffectCard::Construct(const FArguments& InArgs)
{
CardProperty = InArgs._CardProperty;
ChildSlot
[
SNew(SBox)
.WidthOverride(125.0f)
.HeightOverride(125.0f)
[
SNew(SOverlay)
+ SOverlay::Slot()
[
SNew(SButton)
]
+ SOverlay::Slot()
[
SNew(SImage)
.Visibility(EVisibility::HitTestInvisible)
.Image(FUtils::GetBrushFromImage(FUtils::GetResourcesPath("EffectCard.png"), FVector2D(125.0, 125.0)))
]
+ SOverlay::Slot()
[
SNew(SClickEditableText)
.InitTextPtr(&CardProperty->Name)
.OnEdited_Raw(this, &SEffectCard::OnNameEdited)
]
]
];
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

View File

@ -0,0 +1,28 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Cut5/Widgets/DefineGlobal.h"
#include "Widgets/SCompoundWidget.h"
/**
*
*/
class CUT5_API SEffectCard : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SEffectCard)
{
}
SLATE_ARGUMENT(FEffectCardProperty*, CardProperty)
SLATE_END_ARGS()
FEffectCardProperty* CardProperty;
void OnNameEdited(FString New, FString Old);
/** Constructs this widget with InArgs */
void Construct(const FArguments& InArgs);
};

View File

@ -0,0 +1,76 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "SEffectCardGroup.h"
#include "SEffectCard.h"
#include "SlateOptMacros.h"
#include "Widgets/Layout/SExpandableArea.h"
#include "Widgets/Layout/SGridPanel.h"
#include "Widgets/Layout/SScrollBox.h"
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SEffectCardGroup::Construct(const FArguments& InArgs)
{
EffectCardGroup = InArgs._EffectCardGroup;
MainInterface = InArgs._MainInterface;
ChildSlot
[
SNew(SBox)
.WidthOverride(250.0f)
.HeightOverride(250.0f)
[
SNew(SExpandableArea)
.AreaTitle(FText::FromString(TEXT("独立特效")))
.BodyContent()
[
SAssignNew(Contents, SScrollBox)
+ SScrollBox::Slot()
[
SAssignNew(GridPanel, SGridPanel)
]
]
]
];
CallRender();
}
void SEffectCardGroup::CallRender()
{
GridPanel->AddSlot(GridPanel->GetChildren()->Num() % 3, GridPanel->GetChildren()->Num() / 3)
[
SNew(SBox)
[
SNew(SButton)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.OnClicked_Lambda([this]()
{
FEffectCardProperty NewCard;
NewCard.Name = TEXT("未命名");
NewCard.TimelineBinaryPath = FPaths::Combine(FPaths::ProjectSavedDir(), FGlobalData::CurrentProjectName, TEXT("FX"), EffectCardGroup->GroupName, TEXT("未命名.bin"));
MainInterface->AddNewCard(NewCard, EffectCardGroup->GroupName);
return FReply::Handled();
})
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("添加新特效卡")))
]
]
];
for (FEffectCardProperty& Property : EffectCardGroup->Cards)
{
GridPanel->AddSlot(GridPanel->GetChildren()->Num() % 3, GridPanel->GetChildren()->Num() / 3)
[
SNew(SEffectCard)
.CardProperty(&Property)
];
}
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

View File

@ -0,0 +1,43 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Cut5/Interface/CutMainWidgetInterface.h"
#include "Cut5/Widgets/DefineGlobal.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/Layout/SGridPanel.h"
#include "Widgets/Layout/SScrollBox.h"
/**
*
*/
class CUT5_API SEffectCardGroup : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SEffectCardGroup)
{
}
SLATE_ARGUMENT(FEffectCardGroup*, EffectCardGroup)
SLATE_ARGUMENT(ICutMainWidgetInterface*, MainInterface)
SLATE_END_ARGS()
/** Constructs this widget with InArgs */
void Construct(const FArguments& InArgs);
void CallRender();
ICutMainWidgetInterface* MainInterface;
FEffectCardGroup* EffectCardGroup;
/**
* @brief All the effect cards slate instance in this group.
*/
TSharedPtr<SScrollBox> Contents;
/**
* @brief All the effect cards slate instance in this group and formatted.
*/
TSharedPtr<SGridPanel> GridPanel;
};

View File

@ -0,0 +1,138 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "SEffectCardsPanel.h"
#include "SEffectCardGroup.h"
#include "SlateOptMacros.h"
#include "Widgets/Layout/SExpandableArea.h"
#include "Widgets/Layout/SScrollBox.h"
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
// The best approach here would be to write the card
// addition function in a separate "Group" file and
// then call it here. This would improve the code's structure.
// However, I'm too lazy to make the change.
void SEffectCardsPanel::Construct(const FArguments& InArgs)
{
MainInterface = InArgs._MainInterface;
ChildSlot
[
SNew(SBox)
[
SAssignNew(ScrollBox, SScrollBox)
]
];
FEffectCardGroup DedicatedGroup;
DedicatedGroup.bIsDedicated = true;
DedicatedGroup.GroupName = TEXT("独立特效卡");
EffectCardGroups.Add(DedicatedGroup);
FEffectCardProperty CardProperty;
CardProperty.Name = TEXT("鲨鱼卡");
AddNewCard(CardProperty, "");
}
void SEffectCardsPanel::CallRender()
{
ScrollBox->ClearChildren();
for (FEffectCardGroup& Group : EffectCardGroups)
{
ScrollBox->AddSlot()
[
SNew(SEffectCardGroup)
.EffectCardGroup(&Group)
.MainInterface(MainInterface)
];
}
}
void SEffectCardsPanel::AddNewCard(FEffectCardProperty CardProperty, const FString& GroupName)
{
// Get Card Group
FEffectCardGroup* CardGroup = nullptr;
if (GroupName.IsEmpty())
{
CardGroup = GetDedicatedGroupFromName();
}
else
{
CardGroup = GetGroupFromName(GroupName);
}
CardGroup->Cards.Add(CardProperty);
CallRender();
}
void SEffectCardsPanel::RemoveCard(const FGuid& GUID)
{
// Search in all group to find GUID equal to the GUID.
for (FEffectCardGroup& Group : EffectCardGroups)
{
int32 i = 0;
for (FEffectCardProperty& Property : Group.Cards)
{
if (Property.Guid == GUID)
{
Group.Cards.RemoveAt(i);
break;
}
i++;
}
}
CallRender();
}
void SEffectCardsPanel::MoveCard(const FGuid& GUID, const FString& GroupName)
{
FEffectCardProperty CardProperty;
bool bIsFound = false;
for (FEffectCardGroup& Group : EffectCardGroups)
{
int32 i = 0;
for (FEffectCardProperty& Property : Group.Cards)
{
if (Property.Guid == GUID)
{
CardProperty = Property;
Group.Cards.RemoveAt(i);
bIsFound = true;
break;
}
i++;
}
}
if (bIsFound)
{
AddNewCard(CardProperty, GroupName);
}
CallRender();
}
FEffectCardGroup* SEffectCardsPanel::GetGroupFromName(const FString& Name)
{
for (FEffectCardGroup& Group : EffectCardGroups)
{
if (Group.GroupName == Name)
{
return &Group;
}
}
return nullptr;
}
FEffectCardGroup* SEffectCardsPanel::GetDedicatedGroupFromName()
{
for (FEffectCardGroup& Group : EffectCardGroups)
{
if (Group.bIsDedicated == true || Group.GroupName == TEXT("独立特效卡"))
{
return &Group;
}
}
return nullptr;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

View File

@ -0,0 +1,81 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Cut5/Interface/CutMainWidgetInterface.h"
#include "Cut5/Widgets/DefineGlobal.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/Layout/SScrollBox.h"
/**
*
*/
class CUT5_API SEffectCardsPanel : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SEffectCardsPanel)
{
}
SLATE_ARGUMENT(ICutMainWidgetInterface*, MainInterface)
SLATE_END_ARGS()
/** Constructs this widget with InArgs */
void Construct(const FArguments& InArgs);
/**
* @brief Content all group slate instance in this panel.
*/
TSharedPtr<SScrollBox> ScrollBox;
/**
* @brief Main Interface from CutMainWidget.
*/
ICutMainWidgetInterface* MainInterface;
/**
* @brief EffectCardGroups.
* First Element Should be the Dedicated Group.
*/
TArray<FEffectCardGroup> EffectCardGroups;
/**
* @brief Call Render to rerender the panel.
*/
void CallRender();
/**
* @brief Add a new card to the group.
* @param CardProperty Card property.
* @param GroupName Group name can be empty.
*/
void AddNewCard(FEffectCardProperty CardProperty, const FString& GroupName);
/**
* @brief Remove Card from the group.
* @param GUID Card GUID.
*/
void RemoveCard(const FGuid& GUID);
/**
* @brief Move card from one group to another.
* @param GUID Card GUID.
* @param GroupName New group name.
*/
void MoveCard(const FGuid& GUID, const FString& GroupName);
/**
* @brief Get Group Ptr from Group Name.
* @param Name Group Name.
* @return Group Ptr.
*/
FEffectCardGroup* GetGroupFromName(const FString& Name);
/**
* @brief Get Dedicated Group Ptr From Name;
* @return Dedicated Group Ptr.
*/
FEffectCardGroup* GetDedicatedGroupFromName();
};

View File

@ -14,6 +14,7 @@ void SClickEditableText::Construct(const FArguments& InArgs)
{
TextPtr = InArgs._InitTextPtr;
OnEdited = InArgs._OnEdited;
IsNeedUpright = InArgs._IsNeedUpright;
ChildSlot
[
SNew(SVerticalBox)
@ -59,7 +60,7 @@ void SClickEditableText::CreateEditableBox()
TextBlock->SetText(FText::FromString(*TextPtr));
return;
}
TextBlock->SetText(FText::FromString(FUtils::MakeStringUpright(InText.ToString())));
TextBlock->SetText(FText::FromString(IsNeedUpright ? FUtils::MakeStringUpright(InText.ToString()) : InText.ToString()));
Overlay->RemoveSlot(EditableText.ToSharedRef());
if (!OnEdited.ExecuteIfBound(InText.ToString(), *TextPtr))
{

View File

@ -18,6 +18,7 @@ public:
}
SLATE_ARGUMENT(FString*, InitTextPtr)
SLATE_EVENT(FOnEdited, OnEdited)
SLATE_ARGUMENT(bool, IsNeedUpright)
SLATE_END_ARGS()
/** Constructs this widget with InArgs */
@ -27,7 +28,7 @@ public:
TSharedPtr<SOverlay> Overlay;
TSharedPtr<SEditableText> EditableText;
FOnEdited OnEdited;
bool IsNeedUpright = true;
FString* TextPtr;
void CreateEditableBox();
};

View File

@ -13,8 +13,10 @@
#include "STimelinePropertyPanel.h"
#include "STrackBody.h"
#include "STrackHead.h"
#include "FX/SEffectCardsPanel.h"
#include "Widgets/Layout/SConstraintCanvas.h"
#include "Widgets/Layout/SScaleBox.h"
#include "Widgets/Layout/SWidgetSwitcher.h"
#include "Widgets/Views/STreeView.h"
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
@ -85,10 +87,44 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.SizeParam(FAuto())
[
// Property Panel
SNew(STimelinePropertyPanel)
.MainWindow(SharedThis(this))
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
[
SNew(SButton)
.Text(FText::FromString(TEXT("设备列表")))
.OnClicked_Lambda([this]()
{
PropertiesPanelSwitcher->SetActiveWidgetIndex(0);
return FReply::Handled();
})
]
+ SHorizontalBox::Slot()
[
SNew(SButton)
.Text(FText::FromString(TEXT("特效卡")))
.OnClicked_Lambda([this]()
{
PropertiesPanelSwitcher->SetActiveWidgetIndex(1);
return FReply::Handled();
})
]
]
+ SVerticalBox::Slot()
[
SAssignNew(PropertiesPanelSwitcher, SWidgetSwitcher)
+ SWidgetSwitcher::Slot()
[
// Property Panel
SNew(STimelinePropertyPanel)
.MainWindow(SharedThis(this))
]
+ SWidgetSwitcher::Slot()
[
SAssignNew(EffectCardsPanel, SEffectCardsPanel)
.MainInterface(this)
]
]
]
+ SHorizontalBox::Slot()
@ -239,6 +275,11 @@ void SCutMainWindow::OnUpdateSound(uint8* Data, int32 Size)
SoundThread->QueueAudio(Data, Size);
}
void SCutMainWindow::AddNewCard(FEffectCardProperty& CardProperty, FString GroupName)
{
EffectCardsPanel->AddNewCard(CardProperty, GroupName);
}
FTimelinePropertyData* SCutMainWindow::GetResourcePropertyDataPtr(FGuid GUID)
{
if (!GUID.IsValid())

View File

@ -35,7 +35,8 @@ public:
TSharedPtr<SHorizontalBox> PlayerGroupsPanel1;
TSharedPtr<SHorizontalBox> PlayerGroupsPanel2;
TSharedPtr<class SCustomInputPanel> CustomInputPanel;
TSharedPtr<class SWidgetSwitcher> PropertiesPanelSwitcher;
TSharedPtr<class SEffectCardsPanel> EffectCardsPanel;
TArray<TSharedPtr<SPlayerLight>> PlayerLightsSlateInstances;
void Render();
@ -50,6 +51,8 @@ public:
virtual void OnAddNewTrack(ETrackType Type) override;
virtual void OnRemoveTrack(FGuid Guid) override;
virtual void OnUpdateSound(uint8* Data, int32 Size) override;
// 不好 到时候改成 Group Widget 内部操作
virtual void AddNewCard(FEffectCardProperty& CardProperty, FString GroupName) override;
virtual FTimelinePropertyData* GetResourcePropertyDataPtr(FGuid GUID) override;
virtual FString GetGroupName(TSharedPtr<IWidgetInterface> WidgetInterface) override;
};

View File

@ -393,7 +393,7 @@ void SCutTimeline::SaveTimeline(const FString& SavedPath)
{
MemoryWriter << StaticCastSharedPtr<STrackHead>(TrackGroupInstances[i].Head)->TrackData;
}
FFileHelper::SaveArrayToFile(SavedData, *FPaths::Combine(FPaths::ProjectSavedDir(), SavedPath));
FFileHelper::SaveArrayToFile(SavedData, *FPaths::Combine(FPaths::ProjectSavedDir(), FGlobalData::CurrentProjectName, SavedPath));
}
void SCutTimeline::LoadTimeline(const FString& LoadPath)
@ -401,7 +401,7 @@ void SCutTimeline::LoadTimeline(const FString& LoadPath)
TArray<uint8> LoadData;
if (!FPaths::IsDrive(LoadPath))
{
FFileHelper::LoadFileToArray(LoadData, *FPaths::Combine(FPaths::ProjectSavedDir(), LoadPath));
FFileHelper::LoadFileToArray(LoadData, *FPaths::Combine(FPaths::ProjectSavedDir(), FGlobalData::CurrentProjectName, LoadPath));
}
else
{