FReply SFlipbookKeyframeWidget::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) { bool bWasDropHandled = false; UPaperFlipbook* Flipbook = FlipbookBeingEdited.Get(); if ((Flipbook != nullptr) && Flipbook->IsValidKeyFrameIndex(FrameIndex)) { TSharedPtr<FDragDropOperation> Operation = DragDropEvent.GetOperation(); if (!Operation.IsValid()) { } else if (Operation->IsOfType<FAssetDragDropOp>()) { const auto& AssetDragDropOp = StaticCastSharedPtr<FAssetDragDropOp>(Operation); //@TODO: Handle asset inserts // OnAssetsDropped(*AssetDragDropOp); // bWasDropHandled = true; } else if (Operation->IsOfType<FFlipbookKeyFrameDragDropOp>()) { const auto& FrameDragDropOp = StaticCastSharedPtr<FFlipbookKeyFrameDragDropOp>(Operation); FrameDragDropOp->InsertInFlipbook(Flipbook, FrameIndex); bWasDropHandled = true; } } return bWasDropHandled ? FReply::Handled() : FReply::Unhandled(); }
int32 SFlipbookTimeline::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { LayerId = SCompoundWidget::OnPaint(Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled); const float CurrentTimeSecs = PlayTime.Get(); UPaperFlipbook* Flipbook = FlipbookBeingEdited.Get(); const float TotalTimeSecs = (Flipbook != nullptr) ? Flipbook->GetTotalDuration() : 0.0f; const int32 TotalNumFrames = (Flipbook != nullptr) ? Flipbook->GetNumFrames() : 0; const float SlateTotalDistance = SlateUnitsPerFrame * TotalNumFrames; const float CurrentTimeXPos = (CurrentTimeSecs / TotalTimeSecs) * SlateTotalDistance; // Draw a line for the current scrub cursor ++LayerId; TArray<FVector2D> LinePoints; LinePoints.Add(FVector2D(CurrentTimeXPos, 0.f)); LinePoints.Add(FVector2D(CurrentTimeXPos, AllottedGeometry.Size.Y)); FSlateDrawElement::MakeLines( OutDrawElements, LayerId, AllottedGeometry.ToPaintGeometry(), LinePoints, MyClippingRect, ESlateDrawEffect::None, FLinearColor::Red ); return LayerId; }
// Can return null const FPaperFlipbookKeyFrame* SFlipbookKeyframeWidget::GetKeyFrameData() const { UPaperFlipbook* Flipbook = FlipbookBeingEdited.Get(); if ((Flipbook != nullptr) && Flipbook->IsValidKeyFrameIndex(FrameIndex)) { return &(Flipbook->GetKeyFrameChecked(FrameIndex)); } return nullptr; }
void SFlipbookKeyframeWidget::Construct(const FArguments& InArgs, int32 InFrameIndex, TSharedPtr<FUICommandList> InCommandList) { FrameIndex = InFrameIndex; CommandList = MakeShareable(new FUICommandList); CommandList->Append(InCommandList.ToSharedRef()); SlateUnitsPerFrame = InArgs._SlateUnitsPerFrame; FlipbookBeingEdited = InArgs._FlipbookBeingEdited; OnSelectionChanged = InArgs._OnSelectionChanged; // Color each region based on whether a sprite has been set or not for it const auto BorderColorDelegate = [](TAttribute<UPaperFlipbook*> ThisFlipbookPtr, int32 TestIndex) -> FSlateColor { UPaperFlipbook* FlipbookPtr = ThisFlipbookPtr.Get(); const bool bFrameValid = (FlipbookPtr != nullptr) && (FlipbookPtr->GetSpriteAtFrame(TestIndex) != nullptr); return bFrameValid ? FLinearColor::White : FLinearColor::Black; }; ChildSlot [ SNew(SOverlay) +SOverlay::Slot() [ SNew(SBox) .Padding(FFlipbookUIConstants::FramePadding) .WidthOverride(this, &SFlipbookKeyframeWidget::GetFrameWidth) [ SNew(SBorder) .BorderImage(FPaperStyle::Get()->GetBrush("FlipbookEditor.RegionBody")) .BorderBackgroundColor_Static(BorderColorDelegate, FlipbookBeingEdited, FrameIndex) .OnMouseButtonUp(this, &SFlipbookKeyframeWidget::KeyframeOnMouseButtonUp) .ToolTipText(this, &SFlipbookKeyframeWidget::GetKeyframeTooltip) .HAlign(HAlign_Center) .VAlign(VAlign_Center) [ SNew(STextBlock) .ColorAndOpacity(FLinearColor::Black) .Text(this, &SFlipbookKeyframeWidget::GetKeyframeText) ] ] ] +SOverlay::Slot() .HAlign(HAlign_Right) [ SNew(SBox) .WidthOverride(FFlipbookUIConstants::HandleWidth) [ SNew(SFlipbookTrackHandle) .SlateUnitsPerFrame(SlateUnitsPerFrame) .FlipbookBeingEdited(FlipbookBeingEdited) .KeyFrameIdx(FrameIndex) ] ] ]; }
FOptionalSize SFlipbookKeyframeWidget::GetFrameWidth() const { UPaperFlipbook* Flipbook = FlipbookBeingEdited.Get(); if (Flipbook && Flipbook->IsValidKeyFrameIndex(FrameIndex)) { const FPaperFlipbookKeyFrame& KeyFrame = Flipbook->GetKeyFrameChecked(FrameIndex); return FMath::Max<float>(0, KeyFrame.FrameRun * SlateUnitsPerFrame.Get() - FFlipbookUIConstants::HandleWidth); } else { return 1; } }
FReply SFlipbookKeyframeWidget::OnDragDetected(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton)) { UPaperFlipbook* Flipbook = FlipbookBeingEdited.Get(); if ((Flipbook != nullptr) && Flipbook->IsValidKeyFrameIndex(FrameIndex)) { TSharedRef<FFlipbookKeyFrameDragDropOp> Operation = FFlipbookKeyFrameDragDropOp::New( GetFrameWidth().Get(), Flipbook, FrameIndex); return FReply::Handled().BeginDragDrop(Operation); } } return FReply::Unhandled(); }
FText SFlipbookKeyframeWidget::GetKeyframeTooltip() const { UPaperFlipbook* Flipbook = FlipbookBeingEdited.Get(); if ((Flipbook != nullptr) && Flipbook->IsValidKeyFrameIndex(FrameIndex)) { const FPaperFlipbookKeyFrame& KeyFrame = Flipbook->GetKeyFrameChecked(FrameIndex); FText SpriteLine = (KeyFrame.Sprite != nullptr) ? FText::FromString(KeyFrame.Sprite->GetName()) : LOCTEXT("NoSprite", "(none)"); return FText::Format(LOCTEXT("KeyFrameTooltip", "Sprite: {0}\nIndex: {1}\nDuration: {2} frame(s)"), SpriteLine, FText::AsNumber(FrameIndex), FText::AsNumber(KeyFrame.FrameRun)); } else { return LOCTEXT("KeyFrameTooltip_Invalid", "Invalid key frame index"); } }
void SFlipbookTimeline::CheckForRebuild(bool bRebuildAll) { UPaperFlipbook* Flipbook = FlipbookBeingEdited.Get(); const int32 NewNumKeyframes = (Flipbook != nullptr) ? Flipbook->GetNumKeyFrames() : 0; if ((NewNumKeyframes != NumKeyFramesFromLastRebuild) || bRebuildAll) { NumKeyFramesFromLastRebuild = NewNumKeyframes; TimelineTrack->Rebuild(); } const int32 NewNumFrames = (Flipbook != nullptr) ? Flipbook->GetNumFrames() : 0; if ((NewNumFrames != NumFramesFromLastRebuild) || bRebuildAll) { NumFramesFromLastRebuild = NewNumFrames; TimelineHeader->Rebuild(); RebuildPerFrameBG(); } }
void SFlipbookTimeline::OnAssetsDropped(const class FAssetDragDropOp& DragDropOp) { //@TODO: Support inserting in addition to dropping at the end TArray<FPaperFlipbookKeyFrame> NewFrames; for (const FAssetData& AssetData : DragDropOp.AssetData) { if (UObject* Object = AssetData.GetAsset()) { if (UPaperSprite* SpriteAsset = Cast<UPaperSprite>(Object)) { // Insert this sprite as a keyframe FPaperFlipbookKeyFrame& NewFrame = *new (NewFrames) FPaperFlipbookKeyFrame(); NewFrame.Sprite = SpriteAsset; } else if (UPaperFlipbook* FlipbookAsset = Cast<UPaperFlipbook>(Object)) { // Insert all of the keyframes from the other flipbook into this one for (int32 KeyIndex = 0; KeyIndex < FlipbookAsset->GetNumKeyFrames(); ++KeyIndex) { const FPaperFlipbookKeyFrame& OtherFlipbookFrame = FlipbookAsset->GetKeyFrameChecked(KeyIndex); FPaperFlipbookKeyFrame& NewFrame = *new (NewFrames) FPaperFlipbookKeyFrame(); NewFrame = OtherFlipbookFrame; } } } } UPaperFlipbook* ThisFlipbook = FlipbookBeingEdited.Get(); if (NewFrames.Num() && (ThisFlipbook != nullptr)) { const FScopedTransaction Transaction(LOCTEXT("DroppedAssetOntoTimeline", "Insert assets as frames")); ThisFlipbook->Modify(); FScopedFlipbookMutator EditLock(ThisFlipbook); EditLock.KeyFrames.Append(NewFrames); } }
EVisibility SFlipbookTimeline::NoFramesWarningVisibility() const { UPaperFlipbook* Flipbook = FlipbookBeingEdited.Get(); const int32 TotalNumFrames = (Flipbook != nullptr) ? Flipbook->GetNumFrames() : 0; return (TotalNumFrames == 0) ? EVisibility::Visible : EVisibility::Collapsed; }
void SFlipbookTimeline::Construct(const FArguments& InArgs, TSharedPtr<FUICommandList> InCommandList) { FlipbookBeingEdited = InArgs._FlipbookBeingEdited; PlayTime = InArgs._PlayTime; OnSelectionChanged = InArgs._OnSelectionChanged; CommandList = InCommandList; SlateUnitsPerFrame = 120.0f; BackgroundPerFrameSlices = SNew(SHorizontalBox); TimelineHeader = SNew(STimelineHeader) .SlateUnitsPerFrame(this, &SFlipbookTimeline::GetSlateUnitsPerFrame) .FlipbookBeingEdited(FlipbookBeingEdited) .PlayTime(PlayTime); TimelineTrack = SNew(SFlipbookTimelineTrack, CommandList) .SlateUnitsPerFrame(this, &SFlipbookTimeline::GetSlateUnitsPerFrame) .FlipbookBeingEdited(FlipbookBeingEdited) .OnSelectionChanged(OnSelectionChanged); ChildSlot [ SNew(SBorder) .BorderImage( FEditorStyle::GetBrush("ToolPanel.GroupBorder") ) [ SNew(SScrollBox) .Orientation(Orient_Horizontal) .ScrollBarAlwaysVisible(true) +SScrollBox::Slot() [ SNew(SOverlay) // Per-frame background +SOverlay::Slot() .VAlign(VAlign_Fill) [ BackgroundPerFrameSlices.ToSharedRef() ] // Flipbook header and track +SOverlay::Slot() [ SNew(SVerticalBox) +SVerticalBox::Slot() .AutoHeight() .Padding(0,0,0,2) [ TimelineHeader.ToSharedRef() ] +SVerticalBox::Slot() .AutoHeight() [ SNew(SBox) .HeightOverride(FFlipbookUIConstants::FrameHeight) [ TimelineTrack.ToSharedRef() ] ] ] // Empty flipbook instructions + SOverlay::Slot() .VAlign(VAlign_Center) .HAlign(HAlign_Center) [ SNew(STextBlock) .Visibility(this, &SFlipbookTimeline::NoFramesWarningVisibility) .Text(LOCTEXT("EmptyTimelineInstruction", "Right-click here or drop in sprites to add key frames")) ] ] ] ]; UPaperFlipbook* Flipbook = FlipbookBeingEdited.Get(); NumKeyFramesFromLastRebuild = (Flipbook != nullptr) ? Flipbook->GetNumKeyFrames() : 0; NumFramesFromLastRebuild = (Flipbook != nullptr) ? Flipbook->GetNumFrames() : 0; RebuildPerFrameBG(); }