FReply SPaperEditorViewport::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { TotalMouseDelta = 0; if (MouseEvent.GetEffectingButton() == EKeys::RightMouseButton) { // RIGHT BUTTON is for dragging and Context Menu. FReply ReplyState = FReply::Handled(); ReplyState.CaptureMouse( SharedThis(this) ); ReplyState.UseHighPrecisionMouseMovement( SharedThis(this) ); SoftwareCursorPosition = PanelCoordToGraphCoord( MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ) ); // clear any interpolation when you manually pan //DeferredMovementTargetObject = nullptr; return ReplyState; } else if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton) { // START MARQUEE SELECTION. const FVector2D GraphMousePos = PanelCoordToGraphCoord( MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ) ); Marquee.Start( GraphMousePos, FMarqueeOperation::OperationTypeFromMouseEvent(MouseEvent) ); // Trigger a selection update now so that single-clicks without a drag still select something OnSelectionChanged.ExecuteIfBound(Marquee, true); PaperViewportClient->Invalidate(); return FReply::Handled().CaptureMouse( SharedThis(this) ); } else { return FReply::Unhandled(); } }
FSlateRect SPaperEditorViewport::PanelRectToGraphRect( const FSlateRect& PanelSpaceRect ) const { FVector2D UpperLeft = PanelCoordToGraphCoord( FVector2D(PanelSpaceRect.Left, PanelSpaceRect.Top) ); FVector2D LowerRight = PanelCoordToGraphCoord( FVector2D(PanelSpaceRect.Right, PanelSpaceRect.Bottom) ); return FSlateRect( UpperLeft.X, UpperLeft.Y, LowerRight.X, LowerRight.Y ); }
FReply SPaperEditorViewport::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { // We want to zoom into this point; i.e. keep it the same fraction offset into the panel const FVector2D WidgetSpaceCursorPos = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ); FVector2D PointToMaintainGraphSpace = PanelCoordToGraphCoord( WidgetSpaceCursorPos ); const int32 ZoomLevelDelta = FMath::FloorToInt(MouseEvent.GetWheelDelta()); const bool bAllowFullZoomRange = true; const float OldZoomLevel = ZoomLevel; if (bAllowFullZoomRange) { ZoomLevel = FMath::Clamp( ZoomLevel + ZoomLevelDelta, 0, NumZoomLevels-1 ); } else { // Without control, we do not allow zooming out past 1:1. ZoomLevel = FMath::Clamp( ZoomLevel + ZoomLevelDelta, 0, DefaultZoomLevel ); } ZoomLevelFade.Play(this->AsShared()); // Re-center the screen so that it feels like zooming around the cursor. ViewOffset = PointToMaintainGraphSpace - WidgetSpaceCursorPos / GetZoomAmount(); return FReply::Handled(); }
FReply SGraphPanel::OnDrop( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ) { const FVector2D NodeAddPosition = PanelCoordToGraphCoord( MyGeometry.AbsoluteToLocal( DragDropEvent.GetScreenSpacePosition() ) ); FSlateApplication::Get().SetKeyboardFocus(AsShared(), EFocusCause::SetDirectly); TSharedPtr<FDragDropOperation> Operation = DragDropEvent.GetOperation(); if (!Operation.IsValid() || !IsEditable.Get()) { return FReply::Unhandled(); } if (Operation->IsOfType<FGraphEditorDragDropAction>()) { check(GraphObj); TSharedPtr<FGraphEditorDragDropAction> DragConn = StaticCastSharedPtr<FGraphEditorDragDropAction>(Operation); if (DragConn.IsValid() && DragConn->IsSupportedBySchema(GraphObj->GetSchema())) { return DragConn->DroppedOnPanel(SharedThis(this), DragDropEvent.GetScreenSpacePosition(), NodeAddPosition, *GraphObj); } return FReply::Unhandled(); } else if (Operation->IsOfType<FActorDragDropGraphEdOp>()) { TSharedPtr<FActorDragDropGraphEdOp> ActorOp = StaticCastSharedPtr<FActorDragDropGraphEdOp>(Operation); OnDropActor.ExecuteIfBound(ActorOp->Actors, GraphObj, NodeAddPosition); return FReply::Handled(); } else if (Operation->IsOfType<FLevelDragDropOp>()) { TSharedPtr<FLevelDragDropOp> LevelOp = StaticCastSharedPtr<FLevelDragDropOp>(Operation); OnDropStreamingLevel.ExecuteIfBound(LevelOp->StreamingLevelsToDrop, GraphObj, NodeAddPosition); return FReply::Handled(); } else { if(GraphObj != NULL && GraphObj->GetSchema() != NULL) { TArray< FAssetData > DroppedAssetData = AssetUtil::ExtractAssetDataFromDrag( DragDropEvent ); if ( DroppedAssetData.Num() > 0 ) { GraphObj->GetSchema()->DroppedAssetsOnGraph( DroppedAssetData, NodeAddPosition, GraphObj ); return FReply::Handled(); } } return FReply::Unhandled(); } }
FReply SPaperEditorViewport::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { const bool bIsRightMouseButtonDown = MouseEvent.IsMouseButtonDown(EKeys::RightMouseButton); const bool bIsLeftMouseButtonDown = MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton); if (HasMouseCapture()) { // Track how much the mouse moved since the mouse down. const FVector2D CursorDelta = MouseEvent.GetCursorDelta(); TotalMouseDelta += CursorDelta.Size(); if (bIsRightMouseButtonDown) { FReply ReplyState = FReply::Handled(); if (!CursorDelta.IsZero()) { bShowSoftwareCursor = true; } bIsPanning = true; ViewOffset -= CursorDelta / GetZoomAmount(); return ReplyState; } else if (bIsLeftMouseButtonDown) { // TSharedPtr<SNode> NodeBeingDragged = NodeUnderMousePtr.Pin(); // Update the amount to pan panel UpdateViewOffset(MyGeometry, MouseEvent.GetScreenSpacePosition()); const bool bCursorInDeadZone = TotalMouseDelta <= FSlateApplication::Get().GetDragTriggerDistance(); { // We are marquee selecting const FVector2D GraphMousePos = PanelCoordToGraphCoord( MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ) ); Marquee.Rect.UpdateEndPoint(GraphMousePos); return FReply::Handled(); } } } return FReply::Unhandled(); }
TSharedPtr<SWidget> SGraphPanel::OnSummonContextMenu(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { //Editability is up to the user to consider for menu options { // If we didn't drag very far, summon a context menu. // Figure out what's under the mouse: Node, Pin or just the Panel, and summon the context menu for that. UEdGraphNode* NodeUnderCursor = NULL; UEdGraphPin* PinUnderCursor = NULL; { FArrangedChildren ArrangedNodes(EVisibility::Visible); this->ArrangeChildrenForContextMenuSummon(MyGeometry, ArrangedNodes); const int32 HoveredNodeIndex = SWidget::FindChildUnderMouse( ArrangedNodes, MouseEvent ); if (HoveredNodeIndex != INDEX_NONE) { const FArrangedWidget& HoveredNode = ArrangedNodes[HoveredNodeIndex]; TSharedRef<SGraphNode> GraphNode = StaticCastSharedRef<SGraphNode>(HoveredNode.Widget); TSharedPtr<SGraphNode> GraphSubNode = GraphNode->GetNodeUnderMouse(HoveredNode.Geometry, MouseEvent); GraphNode = GraphSubNode.IsValid() ? GraphSubNode.ToSharedRef() : GraphNode; NodeUnderCursor = GraphNode->GetNodeObj(); // Selection should switch to this code if it isn't already selected. // When multiple nodes are selected, we do nothing, provided that the // node for which the context menu is being created is in the selection set. if (!SelectionManager.IsNodeSelected(GraphNode->GetObjectBeingDisplayed())) { SelectionManager.SelectSingleNode(GraphNode->GetObjectBeingDisplayed()); } const TSharedPtr<SGraphPin> HoveredPin = GraphNode->GetHoveredPin( HoveredNode.Geometry, MouseEvent ); if (HoveredPin.IsValid()) { PinUnderCursor = HoveredPin->GetPinObj(); } } } const FVector2D NodeAddPosition = PanelCoordToGraphCoord( MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()) ); TArray<UEdGraphPin*> NoSourcePins; return SummonContextMenu(MouseEvent.GetScreenSpacePosition(), NodeAddPosition, NodeUnderCursor, PinUnderCursor, NoSourcePins, MouseEvent.IsShiftDown()); } return TSharedPtr<SWidget>(); }
bool SGraphPanel::IsRectVisible(const FVector2D &TopLeft, const FVector2D &BottomRight) { return TopLeft >= PanelCoordToGraphCoord( FVector2D::ZeroVector ) && BottomRight <= PanelCoordToGraphCoord( CachedAllottedGeometryScaledSize ); }
/** SWidget interface */ virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override { const bool bIsRightMouseButtonDown = MouseEvent.IsMouseButtonDown( EKeys::RightMouseButton ); const bool bIsLeftMouseButtonDown = MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton ); PastePosition = PanelCoordToGraphCoord( MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ) ); if ( this->HasMouseCapture() ) { const FVector2D CursorDelta = MouseEvent.GetCursorDelta(); // Track how much the mouse moved since the mouse down. TotalMouseDelta += CursorDelta.Size(); if (bIsRightMouseButtonDown) { FReply ReplyState = FReply::Handled(); if( !CursorDelta.IsZero() ) { bShowSoftwareCursor = true; } // Panning and mouse is outside of panel? Pasting should just go to the screen center. PastePosition = PanelCoordToGraphCoord( 0.5 * MyGeometry.Size ); this->bIsPanning = true; ViewOffset -= CursorDelta / GetZoomAmount(); return ReplyState; } else if (bIsLeftMouseButtonDown) { TSharedPtr<SNode> NodeBeingDragged = NodeUnderMousePtr.Pin(); if ( IsEditable.Get() ) { // Update the amount to pan panel UpdateViewOffset(MyGeometry, MouseEvent.GetScreenSpacePosition()); const bool bCursorInDeadZone = TotalMouseDelta <= FSlateApplication::Get().GetDragTriggerDistance(); if ( NodeBeingDragged.IsValid() ) { if ( !bCursorInDeadZone ) { // Note, NodeGrabOffset() comes from the node itself, so it's already scaled correctly. FVector2D AnchorNodeNewPos = PanelCoordToGraphCoord( MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ) ) - NodeGrabOffset; // Dragging an unselected node automatically selects it. SelectionManager.StartDraggingNode(NodeBeingDragged->GetObjectBeingDisplayed(), MouseEvent); // Move all the selected nodes. { const FVector2D AnchorNodeOldPos = NodeBeingDragged->GetPosition(); const FVector2D DeltaPos = AnchorNodeNewPos - AnchorNodeOldPos; if (DeltaPos.Size() > KINDA_SMALL_NUMBER) { MoveSelectedNodes(NodeBeingDragged, AnchorNodeNewPos); } } } return FReply::Handled(); } } if ( !NodeBeingDragged.IsValid() ) { // We are marquee selecting const FVector2D GraphMousePos = PanelCoordToGraphCoord( MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ) ); Marquee.Rect.UpdateEndPoint(GraphMousePos); FindNodesAffectedByMarquee( /*out*/ Marquee.AffectedNodes ); return FReply::Handled(); } } } return FReply::Unhandled(); }