Touch Drag & Drop on windows


#1

Hi
Since around Juce 5.1.2 (I have not pinned it down to a commit) I have issues with drag & drop using touch screen on Windows 10.
I just discovered it now.
I can reproduce it in the Juce Demo:
Tabs & Widgets > Drag & Drop
Try to drag using touch and the drag gets canceled right away.
Can anyone confirm that this is a Juce issue and not some local issue on my end?
I have now compiled with 5.2.0 and the issue is still there


#2

Thanks for the report. There will be a fix for this on develop shortly


#3

Just a heads up… I’m tracking a bug introduced with this commit:

https://github.com/WeAreROLI/JUCE/commit/5d8d37eb878bd1d21cbb2b03edfd3cef01884a97#diff-dbc9a0c7b28164c52c7f234ac9fbc612

I have a ListBox Component which I drop on a class derived from MidiKeyboardComponent… If I revert this change to JUCE circa version 4.3-ish I only get a single itemDropped event on the MidiKeyboardComponent… but with the changes in this commit (and later) I get multiple itemDropped events from one single drag and drop.

I’ll make time tomorrow (later today) to try and figure out the issue.

Cheers,

Rail


#4

Can you reproduce this in the drag and drop section of the JUCE demo? I just tried it out and I’m only seeing a single itemDropped() callback when dragging items from the ListBox.


#5

My issue is fixed.
Thank you!


#6

No I can’t… so I added a DragAndDropMidiKeyboard component to the demo…

(Note: The DragAndDropMidiKeyboard class requires access to some of the private methods in the base class… so I made the private members protected - see the header in the DropBox link)

If you test using that you’ll also find that “itemDropped on Keyboard” only happens once… so I’m looking at the difference in the ListBox…

You added a ListBoxModel class named: SourceItemListboxContents whereas I subclassed ListBox where each row is an CMidiMapListBoxItem Component and in my CMidiMapListBoxItem class I have:

void CMidiMapListBoxItem::mouseDrag (const MouseEvent&)
{
    DBG ("CMidiMapListBoxItem::mouseDrag");
    
    DragAndDropContainer::findParentDragContainerFor (this)->startDragging ("ArticValue", m_pMidiMapObject, m_MoveImage);
}

and

void CMidiMapKeyboard::itemDropped (const SourceDetails &dragSourceDetails)
{
    Logger::writeToLog ("MIDI Map Artic Dropped on keyboard");
}

This generates:

CMidiMapListBoxItem::mouseDrag
CMidiMapListBoxItem::mouseDrag
CMidiMapListBoxItem::mouseDrag
CMidiMapListBoxItem::mouseDrag
MIDI Map Artic Dropped on keyboard: 48 : Beater (Sn Off)
MIDI Map Artic Dropped on keyboard: 48 : Beater (Sn Off)
MIDI Map Artic Dropped on keyboard: 48 : Beater (Sn Off)
:

with itemDropped called 40 times.

If I revert the commit I just get the single itemDropped callback.

Will keep investigating.

Rail


#7

So changing the Demo code with a custom ListBox and using startDragging() will show the issue:

This just has the custom ListBox and the Target Component as in the original demo.

The issue is that the ListBox MouseListener is sending multiple DragImageComponent::mouseUp() callback events.

Rail


#8

So it comes down to the change with having an OwnedArray of DragImageComponent(s).

I can change the code to use a single DragImageComponent as before and it fixes the issue… but it may break it for multi-touch dragging (but shouldn’t).

I added the

ScopedPointer<DragImageComponent> dragImageComponent;

back while also keeping the OwnedArray…

In DragAndDropContainer::startDragging() I added:

    dragImageComponent = new DragImageComponent (dragImage, sourceDescription, sourceComponent, draggingSource, *this, imageOffset);
    
    dragImageComponents.addIfNotAlreadyThere (dragImageComponent);

and in

~DragImageComponent()
    {
        if (owner.dragImageComponent == this)
            owner.dragImageComponent.release();
    
        owner.dragImageComponents.remove (owner.dragImageComponents.indexOf (this), false);
        :
}

Rail


#9

Thanks for looking into this. I’ve just pushed this fix to develop - does it fix the issue for you?


#10

That will work if you explicitly set the last parameter for startDragging()… if it’s the default of/or nullptr you’ll assert every time.

void CMidiMapListBoxItem::mouseDrag (const MouseEvent& event)
{
    DragAndDropContainer::findParentDragContainerFor (this)->startDragging ("ArticValue", m_pMidiMapObject, m_MoveImage, false, nullptr, &event.source); // Must set last param!
}

This is an issue when trying to drag from my TableListBox derived class:

var CVariationTable::getDragSourceDescription (const SparseSet<int>& currentlySelectedRows)
{
    :
    DragAndDropContainer::findParentDragContainerFor (this)->startDragging ("grooveVariation", pVariation, m_DragImage);
    :
}

Rail


#11

If you move things around this will work:

    if (isAlreadyDragging (sourceComponent))
        return;
    
    auto* draggingSource = getMouseInputSourceForDrag (sourceComponent, inputSourceCausingDrag);

    if (draggingSource == nullptr || ! draggingSource->isDragging())
    {
        jassertfalse;   // You must call startDragging() from within a mouseDown or mouseDrag callback!
        return;
    }

    auto lastMouseDown = draggingSource->getLastMouseDownPosition().roundToInt();

Rail


#12

Ah of course. Suppose that’s what I get for trying to write code on a Saturday morning… The fix will be on develop shortly.


#13

Thanks Ed.

Your diligence is appreciated!

Best,

Rail