Hello there,
I have this situation. I have my inventory system UI where I have multiple item slots and I can use a left mouse button to drag and drop items between slots. I want to add now an additional functionality where when you drag an item from the slot and you hover over an empty slot for example and you click the right mouse button while still holding the left mouse button, I would give one count of the holding item to the new slot.
However, I am unable to figure out with UIElements how to detect the right mouse button as I am holding the left mouse button.
I have created this simple example, which pretty much demonstrates what I am after:
using UnityEngine;
using UnityEngine.UIElements;
public class ItemSlotDraggerManipulator : PointerManipulator
{
private bool dragging = false;
public ItemSlotDraggerManipulator()
{
activators.Add(new() { button = MouseButton.LeftMouse });
activators.Add(new() { button = MouseButton.RightMouse });
}
protected override void RegisterCallbacksOnTarget()
{
target.RegisterCallback<PointerDownEvent>(OnPointerDown);
target.RegisterCallback<PointerUpEvent>(OnPointerUp);
}
protected override void UnregisterCallbacksFromTarget()
{
target.UnregisterCallback<PointerDownEvent>(OnPointerDown);
target.UnregisterCallback<PointerUpEvent>(OnPointerUp);
}
private void OnPointerDown(PointerDownEvent evt)
{
if (dragging)
{
if (evt.button == 1)
{
Debug.Log("Down 2"); // Never gets called
}
evt.StopImmediatePropagation(); return;
}
if (!CanStartManipulation(evt) || evt.button != 0) { return; }
dragging = true; target.CapturePointer(evt.pointerId); evt.StopPropagation(); Debug.Log("Down 1");
}
private void OnPointerUp(PointerUpEvent evt)
{
if (!dragging || !target.HasPointerCapture(evt.pointerId) || !CanStopManipulation(evt) || evt.button != 0) { return; }
dragging = false; target.ReleasePointer(evt.pointerId); evt.StopPropagation(); Debug.Log("Up 1");
}
}
public class Main : MonoBehaviour
{
[SerializeField] private UIDocument document = null;
private void Start()
{
var query = document.rootVisualElement.Query("item-slot");
query.ForEach(element =>
{
element.AddManipulator(new ItemSlotDraggerManipulator());
});
}
}
Is there a way to achieve such a result? Would appreciate the help
The PointerDown event sent when you’re pressing both the left button and right button will still have the evt.button be equal to 0, as it was the primary click, but it’ll modify the evt.pressedButtons to reflect the right button being pressed.
So try changing your if statement to check that instead:
if (evt.pressedButtons == 3)
{
Debug.Log("Down 2");
}
From my testing, the problem here is also capturing a PointerEvent. When capturing a PointerEvent you will not receive further OnPointerDown callbacks.
So what @laila-chammaa is saying is true, you need to check “pressedButtons” for “3”, but still OnPointerDown will not get called. Instead, you should replace all your callbacks with the “Mouse” equivalents.
Hmm, unfortunately, it doesn’t appear to be working. I have used your exact code and I get the same result as before.
The idea is that when I drag an item from an X slot to a Y slot and while still dragging I press the other mouse button I will feed the dragging item to a new slot.
So if the X slot item is stackable and the Y slot is either empty or the same item by pressing the other mouse button while dragging is active I will subtract the item count from the dragging slot and will add one to the hover Y slot. At least this is the idea.
I have this, which uses your code, however, once I start dragging and I press the other mouse button, the “Down” log is never displayed.