192 lines
5.4 KiB
C++
192 lines
5.4 KiB
C++
// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
|
|
#include "SPianoRoll.h"
|
|
|
|
#include "SBackgroundBlur.h"
|
|
#include "SGridPanel.h"
|
|
#include "SImage.h"
|
|
#include "SlateOptMacros.h"
|
|
#include "SOverlay.h"
|
|
#include "SPianoKey.h"
|
|
#include "SScaleBox.h"
|
|
#include "SScrollBar.h"
|
|
#include "SScrollBox.h"
|
|
#include "Midi/MidiMessageSequence.h"
|
|
#include "Singleton/MidiSequencer.h"
|
|
#include "PianoRollPanel/SPianoRollPanel.h"
|
|
#include "UI/Style/AronaStyle.h"
|
|
|
|
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
|
|
void SPianoRoll::Construct(const FArguments& InArgs, FMidiMessageSequence* InMidiMessageSequence, FPluginHost* InPluginHost)
|
|
{
|
|
MidiMessageSequence = InMidiMessageSequence;
|
|
VerticalScrollBar = SNew(SScrollBar)
|
|
.Orientation(Orient_Vertical)
|
|
.AlwaysShowScrollbar(true)
|
|
.AlwaysShowScrollbarTrack(true);
|
|
|
|
ChildSlot
|
|
[
|
|
SNew(SGridPanel)
|
|
.FillColumn(0, 1)
|
|
.FillRow(0, 1)
|
|
|
|
+SGridPanel::Slot(0, 0)
|
|
[
|
|
SNew(SOverlay)
|
|
+SOverlay::Slot()
|
|
[
|
|
SNew(SScaleBox)
|
|
.Stretch(EStretch::ScaleToFill)
|
|
.HAlign(HAlign_Center)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SImage)
|
|
.Image(FAronaStyle::GetSlateBrush(PianoRollBackground))
|
|
]
|
|
]
|
|
+SOverlay::Slot()
|
|
[
|
|
SAssignNew(ScrollBox, SScrollBox)
|
|
.ConsumeMouseWheel(EConsumeMouseWheel::Always)
|
|
.ExternalScrollbar(VerticalScrollBar)
|
|
.AnimateWheelScrolling(false)
|
|
.Visibility(EVisibility::SelfHitTestInvisible)
|
|
+SScrollBox::Slot()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
SNew(SPianoKey, InPluginHost)
|
|
.KeyHeight(KeyHeight)
|
|
.KeyWidth(100)
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(1.f)
|
|
[
|
|
SAssignNew(PianoRollPanel, SPianoRollPanel, MidiMessageSequence)
|
|
.FontInfo(FAronaStyle::GetFontInfo(DefaultFontName))
|
|
.NoteImage(FAronaStyle::GetSlateBrush(VolumeMeterBar))
|
|
.SpacingLineColor(FLinearColor::Green)
|
|
.NoteHeight(KeyHeight)
|
|
.OnTargetRangeChanged(this, &SPianoRoll::SetFrameRange)
|
|
.OnYRequestUpdate(this, &SPianoRoll::AddYDelta)
|
|
.OnRequestHScroll(this, &SPianoRoll::OnPanelRequestHScroll)
|
|
]
|
|
]
|
|
]
|
|
]
|
|
+SGridPanel::Slot(1, 0)
|
|
[
|
|
VerticalScrollBar.ToSharedRef()
|
|
]
|
|
+SGridPanel::Slot(0, 1)
|
|
[
|
|
SAssignNew(HorizontalScrollBar, SScrollBar)
|
|
.Orientation(Orient_Horizontal)
|
|
.AlwaysShowScrollbar(true)
|
|
.AlwaysShowScrollbarTrack(true)
|
|
.OnUserScrolled(this, &SPianoRoll::OnHorizontalScrollBarChanged)
|
|
]
|
|
];
|
|
|
|
TargetMidiTickRange = PianoRollPanel->TimeRange;
|
|
const double EndTime = MidiMessageSequence->getEndTime();
|
|
HorizontalScrollBar->SetState(0, TargetMidiTickRange.Size<float>() / EndTime, false);
|
|
}
|
|
|
|
void SPianoRoll::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
|
|
{
|
|
SCompoundWidget::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
|
|
if (AllottedGeometry.Size.X == 0)
|
|
return;
|
|
|
|
// const double Lower = FMath::FInterpTo<double>(PianoRollPanel->TimeRange.GetLowerBoundValue(), TargetMidiTickRange.GetLowerBoundValue(), InDeltaTime, 15.f);
|
|
// const double Upper = FMath::FInterpTo<double>(PianoRollPanel->TimeRange.GetUpperBoundValue(), TargetMidiTickRange.GetUpperBoundValue(), InDeltaTime, 15.f);
|
|
const double Lower = TargetMidiTickRange.GetLowerBoundValue();
|
|
const double Upper = TargetMidiTickRange.GetUpperBoundValue();
|
|
PianoRollPanel->TimeRange.SetLowerBoundValue(Lower);
|
|
PianoRollPanel->TimeRange.SetUpperBoundValue(Upper);
|
|
|
|
const float MidiTickDuration = PianoRollPanel->TimeRange.Size<float>();
|
|
const double EndTime = MidiMessageSequence->getEndTime();
|
|
HorizontalScrollBar->SetState(Lower / EndTime, MidiTickDuration / EndTime, false);
|
|
}
|
|
|
|
FReply SPianoRoll::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
|
{
|
|
if (EnableHorizontalScroll)
|
|
{
|
|
AddFrameRangeDelta(MouseEvent.GetWheelDelta() * -FMidiSequencer::Get().GetTicksPerQuarter());
|
|
return FReply::Unhandled();
|
|
}
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
void SPianoRoll::AddFrameRangeDelta(AudioFrame InDelta)
|
|
{
|
|
double Lower = TargetMidiTickRange.GetLowerBoundValue() + InDelta;
|
|
double Upper = TargetMidiTickRange.GetUpperBoundValue() + InDelta;
|
|
if (Lower < 0)
|
|
{
|
|
Upper -= Lower;
|
|
Lower = 0;
|
|
}
|
|
|
|
TargetMidiTickRange = TRange<AudioFrame>(Lower, Upper);
|
|
}
|
|
|
|
void SPianoRoll::SetFrameRange(TRange<AudioFrame> InMidiRange)
|
|
{
|
|
TargetMidiTickRange = InMidiRange;
|
|
}
|
|
|
|
void SPianoRoll::AddYDelta(float InDelta)
|
|
{
|
|
ScrollBox->SetScrollOffset(ScrollBox->GetScrollOffset() + InDelta);
|
|
}
|
|
|
|
void SPianoRoll::InitScrollBar()
|
|
{
|
|
OnHorizontalScrollBarChanged(0);
|
|
}
|
|
|
|
TSharedPtr<SWidget> SPianoRoll::GetFocusWidget()
|
|
{
|
|
return PianoRollPanel;
|
|
}
|
|
|
|
void SPianoRoll::OnHorizontalScrollBarChanged(float InScrollOffsetFraction)
|
|
{
|
|
const auto& PanelSize = PianoRollPanel->GetTickSpaceGeometry().Size;
|
|
if (PanelSize.X == 0)
|
|
return;
|
|
|
|
const MidiTick EndTime = MidiMessageSequence->getEndTime();
|
|
const MidiTick MidiTickDuration = PianoRollPanel->TimeRange.Size<double>();
|
|
const MidiTick StartTick = EndTime * InScrollOffsetFraction;
|
|
|
|
TargetMidiTickRange = TRange<AudioFrame>(StartTick.Frames(), StartTick.Frames() + MidiTickDuration.Frames());
|
|
|
|
// HorizontalScrollBar->SetState(InScrollOffsetFraction, MidiTickDuration / EndTime, false);
|
|
}
|
|
|
|
void SPianoRoll::OnPanelRequestHScroll(bool InStatus)
|
|
{
|
|
if (InStatus)
|
|
{
|
|
EnableHorizontalScroll = true;
|
|
ScrollBox->SetConsumeMouseWheel(EConsumeMouseWheel::Never);
|
|
}
|
|
else
|
|
{
|
|
EnableHorizontalScroll = false;
|
|
ScrollBox->SetConsumeMouseWheel(EConsumeMouseWheel::Always);
|
|
}
|
|
}
|
|
|
|
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
|