Common UI Common Button Base Drag Drop

Currently we are looking to create a drag drop centric UI utilizing Common UI as our UI base. We have found that the Common Button Base does not allow for drag and drop functionality with out additional wrappers and handling in other UserWidgets. This means that we have to inject a lot of the functionality from the wrapping User Widget into the button itself.

I have looked through all of the SCommonButton, UCommonButtonBase, and UCommonButtonBaseInternal classes and found that non of these really support any drag drop behaviors and they are not setup to bubble that kind of input up to any other layer.

The only way forward that I have found (without modifying the source) is to completely remake the SCommonButton and following classes with some logic to allow for drag drop to take place. This would also create a cascading situation of rebuilding Common List, and Tile Views to allow us to work with drag drop technology.

Is there a better way to achieve this? Are we missing something that was seen during development of Common UI to cause drag drop to not be supported?

Steps to Reproduce

  1. Enable Common UI
  2. Create a quick Common Button that derives from the Common Button Base
  3. Override the widget’s mouse down event
  4. Note that the Mouse Down event is never called
  5. Note that OnPressed also does not use FReplies making getting the Effecting key incredibly roundabout.

Hi there,

We added support for Drag and Drop to Common Button and List Views with Unreal 5.7

If you’re unable to upgrade, you can try cherry picking the change. The main change is CL 42886976 in Perforce (or this commit on GitHub)

Excelent, Thank you!

Hello, we have pulled in that change, but I have noticed that there are no hovered events happening while dragging an object. Is this intended? How might we be able to get around this?

I noticed that there is a capture mouse call which probably ends up forwarding all mouse events to the same widget (probably including hover events). Could this be a lead in the right direction?

Yeah it’s intentional that there are no hover events while dragging, it is due to mouse capture.

Depending on what you’re trying to achieve, OnDragOver is how a widget can react to to being hovered during a drag.

Ah, I see. So we would need to basically “fake” what the style system does then for on hover to work for the On Drag. It would be great to have an option to enable this kind of behavior for the OnDragOver events. I feel like this kind of negates the whole point of styles in Common UI a bit as there’s no way to integrate that with drag drop without modifying the code (I did this already for other reasons, such as extending the styles to have more options).

Thanks for your time! I think this is solved at this point. If I have further issues or questions, Ill open a new ticket.

Hi Dylan,

I’m using 5.7 and noticed that drag drop doesn’t work by default for Common Buttons outside of list views.

The drag is correctly detected, but the operation doesn’t begin.

Looking at the change, I noticed that if nothing binds to OnCommonButtonDragDetected an unhandled reply is returned, even if the operation was created.

COMMONUI_API FReply UCommonButtonBase::HandleButtonDragDetected(const FGeometry& MyGeometry, const FPointerEvent& PointerEvent)
{
	//	This seems strange... If NativeOnDragDetected has been overridden and creates a valid operation, should I reply Handled?
	UDragDropOperation* Operation = nullptr;
	NativeOnDragDetected(MyGeometry, PointerEvent, Operation);

	if (OnCommonButtonDragDetected().IsBound())
	{
		return OnCommonButtonDragDetected().Execute(MyGeometry, PointerEvent);
	}

	return FReply::Unhandled();
}

Unlike how in list views a handled reply with Begin Drag Drop is returned in SCommonButtonTableRow::OnDragDetected.


I’m not sure if this is intended, but to fix the issue I had to subclass Common Button and override HandleButtonDragDetected

FReply UCommonDraggableButton::HandleButtonDragDetected(const FGeometry& MyGeometry, const FPointerEvent& PointerEvent)
{
	UDragDropOperation* DragDropOp = nullptr;
	NativeOnDragDetected(MyGeometry, PointerEvent, DragDropOp);

	if (OnCommonButtonDragDetected().IsBound())
	{
		return OnCommonButtonDragDetected().Execute(MyGeometry, PointerEvent);
	}

	if (DragDropOp)
	{
		FVector2D ScreenCursorPos = PointerEvent.GetScreenSpacePosition();
		FVector2D ScreenDragPosition = MyGeometry.GetAbsolutePosition();
		float DPIScale = UWidgetLayoutLibrary::GetViewportScale(this);
		uint32 PointerIndex = PointerEvent.GetPointerIndex();
		TSharedPtr<SObjectWidget> GCWidget = MyGCWidget.Pin();

		TSharedRef<FUMGDragDropOp> DragDropOpSharedRef = FUMGDragDropOp::New(
			DragDropOp,
			PointerIndex,
			ScreenCursorPos,
			ScreenDragPosition,
			DPIScale, GCWidget.ToSharedRef());
		

		return FReply::Handled().BeginDragDrop(DragDropOpSharedRef);
	}
	
	return FReply::Unhandled();
}


If this is not intended, is it planned to make this behavior work out of the box? and maybe I should create a PR with this change in UCommonButton instead?