bool FUMGSequencerObjectBindingManager::TryGetObjectBindingDisplayName(const TSharedRef<FMovieSceneInstance>& MovieSceneInstance, const FGuid& ObjectGuid, FText& DisplayName) const { // TODO: This gets called every frame for every bound object and could be a potential performance issue for a really complicated animation. TArray<TWeakObjectPtr<UObject>> BindingObjects; GuidToPreviewObjectsMap.MultiFind(ObjectGuid, BindingObjects); TArray<TWeakObjectPtr<UObject>> SlotContentBindingObjects; GuidToSlotContentPreviewObjectsMap.MultiFind(ObjectGuid, SlotContentBindingObjects); if (BindingObjects.Num() == 0 && SlotContentBindingObjects.Num() == 0) { DisplayName = LOCTEXT("NoBoundObjects", "No bound objects"); } else if (BindingObjects.Num() + SlotContentBindingObjects.Num() > 1) { DisplayName = LOCTEXT("Multiple bound objects", "Multilple bound objects"); } else if (BindingObjects.Num() == 1) { if (BindingObjects[0].IsValid()) { DisplayName = FText::FromString(BindingObjects[0].Get()->GetName()); } else { DisplayName = LOCTEXT("InvalidObject", "Invalid Object"); } } else // SlotContentBindingObjects.Num() == 1 { if ( SlotContentBindingObjects[0].IsValid()) { UWidget* SlotContent = Cast<UWidget>(SlotContentBindingObjects[0].Get()); if (FindGuidForObject(*MovieSceneInstance->GetMovieScene(), *SlotContent).IsValid()) { DisplayName = SlotContent->GetParent() != nullptr ? FText::Format(LOCTEXT("SlotWithParentFormat", "{0} Slot"), FText::FromString(SlotContent->GetParent()->GetName())) : FText::FromString(SlotContentBindingObjects[0]->GetClass()->GetName()); } else { FText PanelName = SlotContent->Slot != nullptr && SlotContent->Slot->Parent != nullptr ? FText::FromString(SlotContent->Slot->Parent->GetName()) : LOCTEXT("InvalidPanel", "Invalid Panel"); FText ContentName = FText::FromString(SlotContent->GetName()); DisplayName = FText::Format(LOCTEXT("SlotObject", "{0} ({1} Slot)"), ContentName, PanelName); } } else { DisplayName = LOCTEXT("InvalidSlotContent", "Invalid slot object"); } } return true; }
void FWidgetBlueprintEditor::ExtendSequencerAddTrackMenu( FMenuBuilder& AddTrackMenuBuilder, TArray<UObject*> ContextObjects ) { if ( ContextObjects.Num() == 1 ) { UWidget* Widget = Cast<UWidget>( ContextObjects[0] ); if ( Widget != nullptr && Widget->GetParent() != nullptr && Widget->Slot != nullptr ) { AddTrackMenuBuilder.BeginSection( "Slot", LOCTEXT( "SlotSection", "Slot" ) ); { FUIAction AddSlotAction( FExecuteAction::CreateRaw( this, &FWidgetBlueprintEditor::AddSlotTrack, Widget->Slot ) ); FText AddSlotLabel = FText::Format(LOCTEXT("SlotLabelFormat", "{0} Slot"), FText::FromString(Widget->GetParent()->GetName())); FText AddSlotToolTip = FText::Format(LOCTEXT("SlotToolTipFormat", "Add {0} slot"), FText::FromString( Widget->GetParent()->GetName())); AddTrackMenuBuilder.AddMenuEntry(AddSlotLabel, AddSlotToolTip, FSlateIcon(), AddSlotAction); } AddTrackMenuBuilder.EndSection(); } } }
FReply FCanvasSlotExtension::HandleAnchorDragging(const FGeometry& Geometry, const FPointerEvent& Event, EAnchorWidget::Type AnchorType) { if ( bMovingAnchor && !Event.GetCursorDelta().IsZero() ) { float InverseSize = 1.0f / Designer->GetPreviewScale(); for ( FWidgetReference& Selection : SelectionCache ) { UWidget* PreviewWidget = Selection.GetPreview(); if ( UCanvasPanel* Canvas = Cast<UCanvasPanel>(PreviewWidget->GetParent()) ) { UCanvasPanelSlot* PreviewCanvasSlot = Cast<UCanvasPanelSlot>(PreviewWidget->Slot); FGeometry Geometry; if ( Canvas->GetGeometryForSlot(PreviewCanvasSlot, Geometry) ) { FGeometry CanvasGeometry = Canvas->GetCanvasWidget()->GetCachedGeometry(); FVector2D StartLocalPosition = CanvasGeometry.AbsoluteToLocal(MouseDownPosition); FVector2D NewLocalPosition = CanvasGeometry.AbsoluteToLocal(Event.GetScreenSpacePosition()); FVector2D LocalPositionDelta = NewLocalPosition - StartLocalPosition; FVector2D AnchorDelta = LocalPositionDelta / CanvasGeometry.Size; const FAnchorData OldLayoutData = PreviewCanvasSlot->LayoutData; FAnchorData LayoutData = OldLayoutData; switch ( AnchorType ) { case EAnchorWidget::Center: LayoutData.Anchors.Maximum = BeginAnchors.Maximum + AnchorDelta; LayoutData.Anchors.Minimum = BeginAnchors.Minimum + AnchorDelta; LayoutData.Anchors.Minimum.X = FMath::Clamp(LayoutData.Anchors.Minimum.X, 0.0f, 1.0f); LayoutData.Anchors.Maximum.X = FMath::Clamp(LayoutData.Anchors.Maximum.X, 0.0f, 1.0f); LayoutData.Anchors.Minimum.Y = FMath::Clamp(LayoutData.Anchors.Minimum.Y, 0.0f, 1.0f); LayoutData.Anchors.Maximum.Y = FMath::Clamp(LayoutData.Anchors.Maximum.Y, 0.0f, 1.0f); break; } switch ( AnchorType ) { case EAnchorWidget::Left: case EAnchorWidget::TopLeft: case EAnchorWidget::BottomLeft: LayoutData.Anchors.Minimum.X = BeginAnchors.Minimum.X + AnchorDelta.X; LayoutData.Anchors.Minimum.X = FMath::Clamp(LayoutData.Anchors.Minimum.X, 0.0f, LayoutData.Anchors.Maximum.X); break; } switch ( AnchorType ) { case EAnchorWidget::Right: case EAnchorWidget::TopRight: case EAnchorWidget::BottomRight: LayoutData.Anchors.Maximum.X = BeginAnchors.Maximum.X + AnchorDelta.X; LayoutData.Anchors.Maximum.X = FMath::Clamp(LayoutData.Anchors.Maximum.X, LayoutData.Anchors.Minimum.X, 1.0f); break; } switch ( AnchorType ) { case EAnchorWidget::Top: case EAnchorWidget::TopLeft: case EAnchorWidget::TopRight: LayoutData.Anchors.Minimum.Y = BeginAnchors.Minimum.Y + AnchorDelta.Y; LayoutData.Anchors.Minimum.Y = FMath::Clamp(LayoutData.Anchors.Minimum.Y, 0.0f, LayoutData.Anchors.Maximum.Y); break; } switch ( AnchorType ) { case EAnchorWidget::Bottom: case EAnchorWidget::BottomLeft: case EAnchorWidget::BottomRight: LayoutData.Anchors.Maximum.Y = BeginAnchors.Maximum.Y + AnchorDelta.Y; LayoutData.Anchors.Maximum.Y = FMath::Clamp(LayoutData.Anchors.Maximum.Y, LayoutData.Anchors.Minimum.Y, 1.0f); break; } // Major percentage snapping { const float MajorAnchorLine = 0.1f; const float MajorAnchorLineSnapDistance = 0.1f; if ( LayoutData.Anchors.Minimum.X != OldLayoutData.Anchors.Minimum.X ) { ProximitySnapValue(MajorAnchorLine, MajorAnchorLineSnapDistance, LayoutData.Anchors.Minimum.X); } if ( LayoutData.Anchors.Minimum.Y != OldLayoutData.Anchors.Minimum.Y ) { ProximitySnapValue(MajorAnchorLine, MajorAnchorLineSnapDistance, LayoutData.Anchors.Minimum.Y); } if ( LayoutData.Anchors.Maximum.X != OldLayoutData.Anchors.Maximum.X ) { ProximitySnapValue(MajorAnchorLine, MajorAnchorLineSnapDistance, LayoutData.Anchors.Maximum.X); } if ( LayoutData.Anchors.Maximum.Y != OldLayoutData.Anchors.Maximum.Y ) { ProximitySnapValue(MajorAnchorLine, MajorAnchorLineSnapDistance, LayoutData.Anchors.Maximum.Y); } } // Rebase the layout and restore the old value after calculating the new final layout // result. { PreviewCanvasSlot->SaveBaseLayout(); PreviewCanvasSlot->LayoutData = LayoutData; PreviewCanvasSlot->RebaseLayout(); LayoutData = PreviewCanvasSlot->LayoutData; PreviewCanvasSlot->LayoutData = OldLayoutData; } // If control is pressed reset all positional offset information if ( FSlateApplication::Get().GetModifierKeys().IsControlDown() ) { FMargin NewOffsets = FMargin(0, 0, LayoutData.Anchors.IsStretchedHorizontal() ? 0 : LayoutData.Offsets.Right, LayoutData.Anchors.IsStretchedVertical() ? 0 : LayoutData.Offsets.Bottom); LayoutData.Offsets = NewOffsets; } UWidget* TemplateWidget = Selection.GetTemplate(); UCanvasPanelSlot* TemplateCanvasSlot = CastChecked<UCanvasPanelSlot>(TemplateWidget->Slot); static const FName LayoutDataName(TEXT("LayoutData")); FObjectEditorUtils::SetPropertyValue<UCanvasPanelSlot, FAnchorData>(PreviewCanvasSlot, LayoutDataName, LayoutData); FObjectEditorUtils::SetPropertyValue<UCanvasPanelSlot, FAnchorData>(TemplateCanvasSlot, LayoutDataName, LayoutData); } }; return FReply::Handled(); } } return FReply::Unhandled(); }