Files
AronaSlate/Source/Arona/UI/Widget/PlayList/PlayListPanel/SPlayListPanel.cpp
2024-01-27 19:16:15 +08:00

286 lines
9.4 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "SPlayListPanel.h"
#include "PlayListEdit.h"
#include "Singleton/PortAudioAPI.h"
#include "SConstraintCanvas.h"
#include "SInvalidationPanel.h"
#include "SlateApplication.h"
#include "SlateOptMacros.h"
#include "SScrollBox.h"
#include "SViewport.h"
#include "Singleton/MidiSequencer.h"
#include "Render/UpdatableTexture.h"
#include "UI/Widget/PlayList/SPlayListTimeLine.h"
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SPlayListPanel::Construct(const FArguments& InArgs)
{
PlayListEdit = MakeShareable(new FPlayListEdit(SharedThis(this)));
TrackHeightManager.TrackHeight = InArgs._TrackHeight;
ViewRange = InArgs._FrameRange;
FMidiSequencer::Get().OnCreatePatternInstance.AddRaw(this, &SPlayListPanel::OnCreatePatternInstance);
FMidiSequencer::Get().OnDeletePatternInstance.AddRaw(this, &SPlayListPanel::OnDeletePatternInstance);
ChildSlot
[
SAssignNew(TrackCanvas, SConstraintCanvas)
];
const TMap<EPatternType, TArray<FPattern*>>& Patterns = FMidiSequencer::Get().GetPattern();
for (const auto& Tuple : Patterns)
{
for (const FPattern* Pattern : Tuple.Value)
{
const TArray<FPatternInstance*>& PatternInstances = Pattern->GetInstances();
for (FPatternInstance* Instance : PatternInstances)
{
OnCreatePatternInstance(Instance);
}
}
}
}
int32 SPlayListPanel::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
const auto& Size = AllottedGeometry.Size;
const TRange<AudioFrame>& Range = ViewRange.Get();
const double FrameToPixelScaler = Size.X / Range.Size<double>();
const FMidiSequencer& MidiSequencer = FMidiSequencer::Get();
const AudioFrame Frame = MidiSequencer.FramePos;
// const int32 Denominator = MidiSequencer.Denominator;
// const int32 Numerator = MidiSequencer.Numerator;
const AudioFrame BarFrameCount = MidiSequencer.GetBar().Frames();
const AudioFrame BeatFrameCount = MidiSequencer.GetBeat().Frames();
const AudioFrame RangeBegin = Range.GetLowerBoundValue();
const AudioFrame RangeEnd = Range.GetUpperBoundValue();
++LayerId;
// 绘制轨道间隔线
for (int i = 0; i < TrackCount; ++i)
{
const float TrackPos = TrackHeightManager.GetTrackPos(i);
// const float TrackHeight = GetTrackHeight(i);
TArray<FVector2f> Points;
Points.Add(FVector2f(0, TrackPos));
Points.Add(FVector2f(AllottedGeometry.Size.X, TrackPos));
FSlateDrawElement::MakeLines(
OutDrawElements,
LayerId,
AllottedGeometry.ToPaintGeometry(),
Points,
ESlateDrawEffect::None,
FLinearColor::White,
true,
1.f
);
}
++LayerId;
// 绘制时间间隔线
const AudioFrame BarDelta = FMath::Fmod(RangeBegin.Pos, BarFrameCount);
for (AudioFrame i = RangeBegin - BarDelta; i < RangeEnd; i += BarFrameCount)
{
TArray<FVector2f> Points;
AudioFrame InX = (i - RangeBegin) * FrameToPixelScaler;
Points.Add(FVector2f(InX, 0));
Points.Add(FVector2f(InX, Size.Y));
FSlateDrawElement::MakeLines(
OutDrawElements,
++LayerId,
AllottedGeometry.ToPaintGeometry(),
Points,
ESlateDrawEffect::None,
SpacingLineColor,
true,
SpacingLineThickness
);
}
++LayerId;
const AudioFrame BeatDelta = FMath::Fmod(RangeBegin, BeatFrameCount);
for (float i = RangeBegin - BeatDelta; i < RangeEnd; i += BeatFrameCount)
{
TArray<FVector2f> Points;
Points.Add(FVector2f((i - RangeBegin) * FrameToPixelScaler, 0));
Points.Add(FVector2f((i - RangeBegin) * FrameToPixelScaler, Size.Y));
FSlateDrawElement::MakeLines(
OutDrawElements,
LayerId,
AllottedGeometry.ToPaintGeometry(),
Points,
ESlateDrawEffect::None,
SpacingLineColor,
true,
SpacingLineThickness
);
}
++LayerId;
{
const AudioFrame CurrentFrameX = (Frame - RangeBegin) * FrameToPixelScaler;
TArray<FVector2f> Points;
Points.Add(FVector2f(CurrentFrameX, 0));
Points.Add(FVector2f(CurrentFrameX, Size.Y));
FSlateDrawElement::MakeLines(
OutDrawElements,
++LayerId,
AllottedGeometry.ToPaintGeometry(),
Points,
ESlateDrawEffect::None,
FLinearColor::Red,
true,
1
);
}
LayerId = PlayListEdit->OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
}
FVector2D SPlayListPanel::ComputeDesiredSize(float LayoutScaleMultiplier) const
{
FVector2D Size;
Size.X = GetTickSpaceGeometry().Size.X;
Size.Y = TrackHeightManager.GetTrackHeight(TrackCount - 1) + TrackHeightManager.GetTrackPos(TrackCount - 1);
return Size;
}
FReply SPlayListPanel::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
return PlayListEdit->OnMouseButtonDown(MyGeometry, MouseEvent);
}
FReply SPlayListPanel::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
return PlayListEdit->OnMouseButtonUp(MyGeometry, MouseEvent);
}
FReply SPlayListPanel::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
return PlayListEdit->OnMouseMove(MyGeometry, MouseEvent);
}
FReply SPlayListPanel::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& InMouseEvent)
{
return SCompoundWidget::OnMouseWheel(MyGeometry, InMouseEvent);
}
FReply SPlayListPanel::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent)
{
return PlayListEdit->OnKeyDown(MyGeometry, InKeyEvent);
}
FReply SPlayListPanel::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent)
{
return PlayListEdit->OnKeyUp(MyGeometry, InKeyEvent);
}
float SPlayListPanel::MidiTickToPixel(MidiTick InMidiTick) const
{
return FrameToPixel(InMidiTick.Frames());
}
float SPlayListPanel::FrameToPixel(AudioFrame InFrame) const
{
const TRange<double> WidgetRange(0, GetTickSpaceGeometry().Size.X);
const TRange<AudioFrame>& CurrentRange = ViewRange.Get();
const double FrameBegin = CurrentRange.GetLowerBoundValue();
const double FrameEnd = CurrentRange.GetUpperBoundValue();
const TRange<double> TempSampleRange(FrameBegin, FrameEnd);
return FMath::GetMappedRangeValueClamped<double>(TempSampleRange, WidgetRange, InFrame);
}
AudioFrame SPlayListPanel::GetSampleToPixelScaler() const
{
return GetTickSpaceGeometry().Size.X / ViewRange.Get().Size<AudioFrame>();
}
AudioFrame SPlayListPanel::GetPixelToSampleScaler() const
{
return ViewRange.Get().Size<AudioFrame>() / static_cast<double>(GetTickSpaceGeometry().Size.X);
}
FMargin SPlayListPanel::CalculatePatternInstancePos(FPatternInstance* PatternInstance) const
{
const double Scaler = GetSampleToPixelScaler();
check(PatternInstance->TrackIndex >= 0)
const TRange<AudioFrame>& Range = ViewRange.Get();
FMargin Offset;
const AudioFrame XOffset = PatternInstance->Pos - Range.GetLowerBoundValue();
Offset.Left = XOffset.Pos * Scaler; // X
Offset.Left = FMath::Max(Offset.Left, 0.0f);
Offset.Top = TrackHeightManager.GetTrackPos(PatternInstance->TrackIndex); // Y
Offset.Bottom = TrackHeightManager.GetTrackHeight(PatternInstance->TrackIndex); // Height
float LeftWidth = (PatternInstance->GetLength() + PatternInstance->Pos) - Range.GetLowerBoundValue();
LeftWidth = FMath::Min(PatternInstance->GetLength().Pos, LeftWidth);
Offset.Right = LeftWidth * Scaler; // Width
Offset.Right = FMath::Min(Offset.Right, GetTickSpaceGeometry().Size.X - Offset.Left);
return Offset;
}
void SPlayListPanel::OnCreatePatternInstance(FPatternInstance* PatternInstance)
{
const TAttribute<FMargin> Offset = TAttribute<FMargin>::Create(TAttribute<FMargin>::FGetter::CreateSP(this, &SPlayListPanel::CalculatePatternInstancePos, PatternInstance));
TrackCanvas->AddSlot()
.Anchors(FAnchors(0, 0, 0, 0))
.Alignment(FVector2D(0, 0))
.Offset(Offset)
[
// SNew(SInvalidationPanel)
// [
PlayListEdit->CreatePatternInstanceWidget(PatternInstance)
// ]
];
}
void SPlayListPanel::OnDeletePatternInstance(FPatternInstance* PatternInstance)
{
TPanelChildren<SConstraintCanvas::FSlot>* Children = (TPanelChildren<SConstraintCanvas::FSlot>*)TrackCanvas->GetChildren();
for (int i = 0; i < Children->Num(); ++i)
{
TSharedRef<SWidget> Widget = Children->GetChildAt(i);
// TSharedRef<SInvalidationPanel> InvalidationPanel = StaticCastSharedRef<SInvalidationPanel>(Widget);
// InvalidationPanel->SetCanCache(false);
// TSharedRef<SWidget> SharedRef = InvalidationPanel->GetChildren()->GetChildAt(0);
// InvalidationPanel->SetCanCache(true);
TSharedRef<SPatternInstance> InstanceWidget = StaticCastSharedRef<SPatternInstance>(Widget);
if (InstanceWidget->GetPatternInstance() == PatternInstance)
{
Children->RemoveAt(i);
break;
}
}
}
void SPlayListPanel::UpdateAllPatternInstance()
{
TPanelChildren<SConstraintCanvas::FSlot>* Children = (TPanelChildren<SConstraintCanvas::FSlot>*)TrackCanvas->GetChildren();
for (int i = 0; i < Children->Num(); ++i)
{
TSharedRef<SWidget> Widget = Children->GetChildAt(i);
TSharedRef<SInvalidationPanel> InvalidationPanel = StaticCastSharedRef<SInvalidationPanel>(Widget);
InvalidationPanel->SetCanCache(false);
TSharedRef<SWidget> SharedRef = InvalidationPanel->GetChildren()->GetChildAt(0);
InvalidationPanel->SetCanCache(true);
TSharedRef<SPatternInstance> InstanceWidget = StaticCastSharedRef<SPatternInstance>(SharedRef);
InstanceWidget->RequestUpdate();
// InstanceWidget->Invalidate(EInvalidateWidgetReason::Paint);
}
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION