// 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 Range = FrameRange.Get(); const auto& Size = AllottedGeometry.Size; const float FrameToPixelScaler = Size.X / Range.Size(); const int32 StepRate = FMath::FloorToInt(Step / SubStep); if (StepRate < 0) return LayerId; const int32 MakerCount = FMath::CeilToInt(Range.Size() / 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 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 Range = FrameRange.Get(); const float FrameToPixelScaler = Size.X / Range.Size(); 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