139 lines
4.5 KiB
C++
139 lines
4.5 KiB
C++
// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
|
|
#include "SPlayList.h"
|
|
|
|
#include "SlateOptMacros.h"
|
|
#include "SPlayListTimeLine.h"
|
|
#include "PlayListPanel/SPlayListPanel.h"
|
|
#include "SScrollBox.h"
|
|
|
|
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
|
|
void SPlayList::Construct(const FArguments& InArgs)
|
|
{
|
|
FrameRange = TRange<AudioFrame>(0, FMidiSequencer::Get().GetBar().Frames() * 16.0);
|
|
TargetFrameRange = FrameRange;
|
|
|
|
ChildSlot
|
|
[
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(0, 0, 12, 0)
|
|
[
|
|
SAssignNew(TimeLine, SPlayListTimeLine)
|
|
.FrameRange(this, &SPlayList::GetFrameRange)
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(1.f)
|
|
[
|
|
SAssignNew(ScrollBox, SScrollBox)
|
|
.AnimateWheelScrolling(true)
|
|
+SScrollBox::Slot()
|
|
[
|
|
SAssignNew(PlayListPanel, SPlayListPanel)
|
|
.TrackHeight(64)
|
|
.FrameRange(this, &SPlayList::GetFrameRange)
|
|
]
|
|
]
|
|
];
|
|
}
|
|
|
|
void SPlayList::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
|
|
{
|
|
SCompoundWidget::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
|
|
FrameRange.SetLowerBoundValue(FMath::FInterpTo<double>(FrameRange.GetLowerBoundValue(), TargetFrameRange.GetLowerBoundValue(), InDeltaTime, 20.f));
|
|
FrameRange.SetUpperBoundValue(FMath::FInterpTo<double>(FrameRange.GetUpperBoundValue(), TargetFrameRange.GetUpperBoundValue(), InDeltaTime, 20.f));
|
|
}
|
|
|
|
FReply SPlayList::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent)
|
|
{
|
|
if (!InKeyEvent.IsRepeat() && InKeyEvent.GetKey() == EKeys::SpaceBar)
|
|
FMidiSequencer::Get().TogglePlay();
|
|
if (!InKeyEvent.IsRepeat() && InKeyEvent.GetKey() == EKeys::LeftControl)
|
|
{
|
|
Zooming = true;
|
|
ScrollBox->SetConsumeMouseWheel(EConsumeMouseWheel::Never);
|
|
}
|
|
if (!InKeyEvent.IsRepeat() && InKeyEvent.GetKey() == EKeys::LeftShift)
|
|
{
|
|
HorizonScrolling = true;
|
|
ScrollBox->SetConsumeMouseWheel(EConsumeMouseWheel::Never);
|
|
}
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FReply SPlayList::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent)
|
|
{
|
|
if (InKeyEvent.GetKey() == EKeys::LeftControl)
|
|
Zooming = false;
|
|
if (InKeyEvent.GetKey() == EKeys::LeftShift)
|
|
HorizonScrolling = false;
|
|
if (!Zooming && !HorizonScrolling)
|
|
ScrollBox->SetConsumeMouseWheel(EConsumeMouseWheel::Always);
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FReply SPlayList::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& InMouseEvent)
|
|
{
|
|
if (Zooming)
|
|
{
|
|
const AudioFrame MinRange = FMidiSequencer::Get().GetBeat() * 4;
|
|
|
|
const TRange<AudioFrame>& CurrentRange = TargetFrameRange;
|
|
const AudioFrame WheelDelta = InMouseEvent.GetWheelDelta() * GetScalerLevel() * 2; // 乘以2是因为MousePosPercent
|
|
|
|
if (WheelDelta.Pos > 0 && CurrentRange.Size<AudioFrame>() <= MinRange)
|
|
return FReply::Handled();
|
|
|
|
const FGeometry& PlayListPanelGeometry = PlayListPanel->GetTickSpaceGeometry();
|
|
const FVector2f& PanelLocalMouse = PlayListPanelGeometry.AbsoluteToLocal(InMouseEvent.GetScreenSpacePosition());
|
|
const double MousePosPercent = PanelLocalMouse.X / PlayListPanelGeometry.Size.X;
|
|
|
|
AudioFrame Low = FMath::Max(0.f, CurrentRange.GetLowerBoundValue() + WheelDelta * MousePosPercent);
|
|
AudioFrame High = FMath::Max(ExternRange, CurrentRange.GetUpperBoundValue() - WheelDelta * (1 - MousePosPercent));
|
|
|
|
// High = FMath::Min(High, GetDurationWithExtern()); // 不限制缩放的最大范围
|
|
// 限制最小范围
|
|
if (WheelDelta.Pos > 0 && High - Low <= MinRange)
|
|
{
|
|
const AudioFrame Mid = (Low + High) / 2.0;
|
|
Low = Mid - MinRange.Pos / 2;
|
|
High = Mid + MinRange.Pos / 2;
|
|
}
|
|
TargetFrameRange = TRange<AudioFrame>(Low, High);
|
|
}
|
|
|
|
if (HorizonScrolling)
|
|
{
|
|
const TRange<AudioFrame>& CurrentRange = TargetFrameRange;
|
|
const AudioFrame WheelDelta = InMouseEvent.GetWheelDelta() * GetScalerLevel();
|
|
const AudioFrame Size = CurrentRange.Size<AudioFrame>();
|
|
const AudioFrame Low = FMath::Max(0.f, CurrentRange.GetLowerBoundValue() - WheelDelta);
|
|
const AudioFrame High = FMath::Max(Low + Size, CurrentRange.GetUpperBoundValue() - WheelDelta);
|
|
|
|
TargetFrameRange = TRange<AudioFrame>(Low, High);
|
|
}
|
|
|
|
return SCompoundWidget::OnMouseWheel(MyGeometry, InMouseEvent);
|
|
}
|
|
|
|
AudioFrame SPlayList::GetScalerLevel()
|
|
{
|
|
const MidiTick Scaler = PlayListPanel->GetPixelToSampleScaler().Ticks();
|
|
const FMidiSequencer& Sequencer = FMidiSequencer::Get();
|
|
const MidiTick Bar = Sequencer.GetBeat();
|
|
return Bar;
|
|
|
|
if (Scaler > Bar)
|
|
return Bar;
|
|
const MidiTick Beat = Sequencer.GetBeat();
|
|
if (Scaler > Beat)
|
|
return Beat;
|
|
return Sequencer.GetTicksPerQuarter();
|
|
}
|
|
|
|
|
|
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
|