AronaSlate/Source/Arona/UI/Widget/PlayList/SPlayListTimeLine.cpp
2024-01-25 11:21:15 +08:00

112 lines
3.6 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "SPlayListTimeLine.h"
#include "SlateOptMacros.h"
#include "Singleton/MidiSequencer.h"
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SPlayListTimeLine::Construct(const FArguments& InArgs)
{
FrameRange = InArgs._FrameRange;
/*
ChildSlot
[
// Populate the widget
];
*/
MainStepColor = FLinearColor(0.2f, 0.2f, 0.2f, 1.f);
SubStepColor = FLinearColor(0.1f, 0.1f, 0.1f, 1.f);
}
int32 SPlayListTimeLine::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
const AudioFrame Step = FMidiSequencer::Get().GetBar().Frames();
const AudioFrame SubStep = FMidiSequencer::Get().GetBeat().Frames();
const TRange<AudioFrame> Range = FrameRange.Get();
const auto& Size = AllottedGeometry.Size;
const float FrameToPixelScaler = Size.X / Range.Size<float>();
const int32 StepRate = FMath::FloorToInt(Step / SubStep);
if (StepRate < 0)
return LayerId;
const int32 MakerCount = FMath::CeilToInt(Range.Size<float>() / Step) + 1;
const int32 SubMakerLineCount = StepRate * MakerCount + 1;
const float Offset = FMath::Fmod(Range.GetLowerBoundValue(), Step);
// Push clip rect
FSlateClippingZone ClippingZone(AllottedGeometry);
OutDrawElements.PushClip(ClippingZone);
++LayerId;
// const float SubLinePadding = AllottedGeometry.Size.Y * 0.4f;
const FPaintGeometry LinePaintGeometry = AllottedGeometry.ToPaintGeometry();
for (int i = 0; i < SubMakerLineCount; ++i)
{
const bool bIsSubMaker = i % StepRate != 0;
const float X = (i * SubStep - Offset) * FrameToPixelScaler;
// const float YPadding = bIsSubMaker ? SubLinePadding : 0;
TArray<FVector2D> Points;
Points.Add(FVector2D(X, 0));
Points.Add(FVector2D(X, AllottedGeometry.Size.Y));
FSlateDrawElement::MakeLines(OutDrawElements, LayerId, LinePaintGeometry, Points, ESlateDrawEffect::None, bIsSubMaker ? SubStepColor : MainStepColor, true, 1.f);
}
OutDrawElements.PopClip();
return LayerId;
}
FReply SPlayListTimeLine::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
{
SetTimePos(MyGeometry, MouseEvent);
return FReply::Handled().CaptureMouse(AsShared());
}
return FReply::Unhandled();
}
FReply SPlayListTimeLine::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
return FReply::Handled().ReleaseMouseCapture();
return FReply::Unhandled();
}
FReply SPlayListTimeLine::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
{
SetTimePos(MyGeometry, MouseEvent);
}
return FReply::Handled();
}
void SPlayListTimeLine::SetTimePos(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
const auto& Size = MyGeometry.Size;
const TRange<AudioFrame> Range = FrameRange.Get();
const float FrameToPixelScaler = Size.X / Range.Size<float>();
const float X = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()).X;
const bool NoSnap = MouseEvent.GetModifierKeys().IsAltDown();
AudioFrame Frame = X / FrameToPixelScaler + Range.GetLowerBoundValue();
if (!NoSnap)
Frame = FMath::GridSnap(Frame.Pos, FMidiSequencer::Get().GetBeat().Frames());
if (Frame.Pos < 0)
Frame = 0;
if (LastFrame == Frame)
return;
LastFrame = Frame;
FMidiSequencer::Get().FramePos = Frame;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION