// Fill out your copyright notice in the Description page of Project Settings. #include "ChannelRackMidiThumbnail.h" #include "SImage.h" #include "SInvalidationPanel.h" #include "SlateApplication.h" #include "SlateOptMacros.h" #include "SScrollBox.h" #include "SViewport.h" #include "Midi/MidiMessageSequence.h" #include "Singleton/MidiSequencer.h" #include "UI/Widget/MainWindow.h" #include "UI/Widget/SUpdatableImage.h" #include "UI/Widget/Thumbnail.h" #include "UI/Widget/WindowManager.h" #include "UI/Widget/PianoRoll/SPianoRoll.h" BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION SChannelRackMidiThumbnail::~SChannelRackMidiThumbnail() { SetPattern(nullptr); } void SChannelRackMidiThumbnail::SetPattern(FMidiPattern* InPattern) { if (CurrentPattern) { CurrentPattern->OnChanged.RemoveAll(this); CurrentPattern->OnPlay.RemoveAll(this); } if (!InPattern) return; CurrentPattern = InPattern; CurrentPattern->OnChanged_MainThread.AddRaw(this, &SChannelRackMidiThumbnail::OnChanged); CurrentPattern->OnPlay.AddRaw(this, &SChannelRackMidiThumbnail::OnPatternPlay); OnChanged(PluginHost, &InPattern->GetSequence(PluginHost)); } void SChannelRackMidiThumbnail::Construct(const FArguments& InArgs, FPluginHost* InPluginHost) { PluginHost = InPluginHost; SetPattern(InArgs._Pattern); ChildSlot [ SNew(SInvalidationPanel) [ SAssignNew(UpdatableImage, SUpdatableImage) .OnPostResize(this, &SChannelRackMidiThumbnail::UpdateMidiThumbnail) .UpdateInterval(0) ] ]; if (InArgs._Pattern) OnChanged(PluginHost, &InArgs._Pattern->GetSequence(InPluginHost)); } FReply SChannelRackMidiThumbnail::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { if (!CurrentPattern) return FReply::Unhandled(); FMidiMessageSequence* MidiSequence = &CurrentPattern->GetSequence(PluginHost); TSharedPtr PianoRoll = SNew(SPianoRoll, MidiSequence, PluginHost); FWindowManager::Get().GetMainWindow()->CreateChildWindow( FVector2D(100, 100), TEXT(""), PianoRoll.ToSharedRef() ); PianoRoll->InitScrollBar(); return FReply::Unhandled(); } int32 SChannelRackMidiThumbnail::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { LayerId = SCompoundWidget::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled); if (CurrentPattern) { const double EndTime = CurrentPattern->GetLength(); const double CurrentPercent = LastPatternPos / EndTime * (double)AllottedGeometry.Size.X; TArray Points; Points.Add(FVector2f(CurrentPercent, 0)); Points.Add(FVector2f(CurrentPercent, AllottedGeometry.Size.Y)); FSlateDrawElement::MakeLines( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(), Points, ESlateDrawEffect::None, FLinearColor::Red, true, 1.f ); } return LayerId; } void SChannelRackMidiThumbnail::OnChanged(FPluginHost* Host, FMidiMessageSequence* Changed) { if (Host != PluginHost) return; UpdatableImage->NeedRedraw(); } void SChannelRackMidiThumbnail::OnPatternPlay(FPatternInstance* PatternInstance, AudioFrame PatternTick, uint32 Length) { LastPatternPos = PatternTick; } void SChannelRackMidiThumbnail::UpdateMidiThumbnail(FImageData& ImageData) { if (!CurrentPattern) return; const FMidiMessageSequence* MidiSequence = &CurrentPattern->GetSequence(PluginHost); ImageData.ClearColor(FColor::Black); Thumbnail::GenerateMidiThumbnail(MidiSequence, ImageData); } END_SLATE_FUNCTION_BUILD_OPTIMIZATION