Changing the mouse cursor to CopyingCursor when shift held down during drag operation

I have a TableListBox (in a plugin project) which I’m allowing rows to be re-ordered with DragAndDropContainer/DragAndDropTarget combo, which is working nicely.
I also can hold down shift when dropping a row to create a copy, which is also working nicely.
What I would like to do is change the mouse cursor to CopyingCursor whilst shift key is down during the drag operation.
I tried using setMouseCursor on my TableListBox but that didn’t work.
The closest I’ve managed to get this working is:

        auto mods = ModifierKeys::getCurrentModifiers();
        myCursor = MouseCursor(mods.isShiftDown() ? MouseCursor::CopyingCursor : MouseCursor::NormalCursor);
        Desktop::getInstance().getMainMouseSource().showMouseCursor(myCursor);

but I only see brief flashes of the copying cursor (presumably DragAndDropContainer is changing the cursor back to default?).

This must be a common thing to do, what have I missed?

The MouseEvent has a MouseInputSource, on which you can call showMouseCursor (const MouseCursor& cursor)

if (event.mods.isAltDown())
    event.source.showMouseCursor (MouseCursor::CopyingCursor);
else
    event.source.showMouseCursor (MouseCursor::DraggingHandCursor);

Oh, reading again before pressing send, I realise it will have the same effect like you already have :frowning:

Anyway, it’s a shortcut :wink:

If you need the DragAndDropContainer, you can use findParentDragContainerFor():

auto* container = DragAndDropContainer::findParentDragContainerFor (event.originalComponent);

But I don’t see, how you would change the cursor there…

Good luck

1 Like

I dug a bit further down into JUCE internals, and it seems that DragImageComponent is calling forceMouseCursorUpdate() on the main mouse source, which is calling revealCursor() which is setting up a MouseCursor mc (MouseCursor::NormalCursor); and showing it. Which would explain why I managed to only see brief flashes of the CopyingCursor and seems to suggest that what I’m trying to achieve is impossible :frowning:

Hey Richie,
I’m having the same issue. Did you ever find a solution?

  • Matt

But the next lines are:

        if (auto* current = getComponentUnderMouse())
            mc = current->getLookAndFeel().getMouseCursorFor (*current);

So, you should be able to set a Look&Feel for that component, and return the desired mouse cursor in its getMouseCursorFor() function, right?

1 Like

Thanks, I suppose I can fix this via LookAndFeel as you suggest. That will make this function work.

void revealCursor (bool forcedUpdate)
    {
        MouseCursor mc (MouseCursor::NormalCursor);

        if (auto* current = getComponentUnderMouse())
            mc = current->getLookAndFeel().getMouseCursorFor (*current);

        showMouseCursor (mc, forcedUpdate);
    }

Changing the LookAndFeel of the ListBox when a copy operation is being performed doesn’t seem like the most intuitive solution. I have to think someone has figured this out.

You don’t have to change the Look&Feel. You can just add the ability to set a flag in the Look&Feel that is already attached to your component(s), and just query that flag in your getMouseCursor() function to determine which cursor to return. When set, return the copy cursor. When not set, return the normal cursor.

Got it. Thanks @HowardAntares