Problem with drag and drop from a ListBox


#1

I have a listbox which uses drag and drop. If I have multiple instances of my plugin, it is possible to drag from one instance to the other. There are two problems.

  1. If instance A is covering instance B, and instance A is top most, juce will pick instance B as the drop destination depending on the order of windows. It should pick the instance that is on top, but it starts from the back of the list, apparently. See findDesktopComponentBelow() in juce_DragAndDropContainer.cpp

  2. There is no way to turn off external drag and drop in the listbox, as it defaults to true. See line 129 of juce_Listbox.cpp.

  3. There does not appear to be a way to add this functionality in a sub-class, so for now, I have just edited the Juce code with an optional flag to allow external dragging from list boxes.

-Joseph


#2

I’ve just pushed a fix for 1.

Will have a look at the others tomorrow.


#3

Awesome. Thank you t0m. (=


#4

In your DragAndDropTarget can you just do

bool isInterestedInDragSource (const SourceDetails& details) override
{
    return details.sourceComponent.get() == &yourListBox;
}

?


#5

That was the first thing I tried. Unfortunately, in that case, if they are overlapping, then it won’t allow you to drop on the area where the two instances intersect.


#6

If the plug-in windows are overlapping? I can’t reproduce that in a simple test case.


#7

I wasn’t able to at first too. My plugin window has a component that covers the entire plugin window and is a draganddroptarget and also a draganddropcontainer. The listbox is inside this window.

I was using this code to see if its the same instance.

bool isInterestedInDragSource(const SourceDetails &dragSourceDetails)
{
Component *topForSource = dragSourceDetails.sourceComponent->getTopLevelComponent();
Component *topForCur = getTopLevelComponent();
if ( topForCur == topForSource )
{
return true;
}
}

  1. I place the first instance on the top left and then the second instance on the bottom right (overlapping)
  2. Drag from the 1st instance on the left and drag to the right to the intersecting area and attempt to drop

I can shoot a video if you still can’t repro. Thanks again!


#8

A video would be helpful and/or some source code. I’m using the following which must be pretty similar to what you’re describing:

#pragma once

#include "../JuceLibraryCode/JuceHeader.h"
#include "PluginProcessor.h"

class DragAndDropTestAudioProcessorEditor  : public AudioProcessorEditor,
                                             public DragAndDropContainer,
                                             public DragAndDropTarget
{
public:
    DragAndDropTestAudioProcessorEditor (DragAndDropTestAudioProcessor& p)
        : AudioProcessorEditor (&p), processor (p)
    {
        lb.setRowHeight (30);
        addAndMakeVisible (lb);
        addChildComponent (&text);

        setSize (400, 300);
    }

    ~DragAndDropTestAudioProcessorEditor() {}

    bool isInterestedInDragSource (const SourceDetails& dragSourceDetails) override
    {
        if (auto* source = dragSourceDetails.sourceComponent.get())
            return getTopLevelComponent() == source->getTopLevelComponent();

        return false;
    }

    void itemDropped (const SourceDetails& dragSourceDetails) override
    {
        text.setVisible (true);
    }

    void paint (Graphics& g) override
    {
        g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
    }

    void resized() override
    {
        text.setBounds (0, 0, 200, 200);
        lb.centreWithSize (90, 90);
    }

private:
    struct MyListBoxModel : public ListBoxModel
    {
        int getNumRows() override { return 3; }

        void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool) override
        {
            g.setColour (Colours::cyan);
            Rectangle<int> bounds (0, 0, width, height);
            g.fillRect (bounds.reduced (1));
        }

        var getDragSourceDescription (const SparseSet<int>& rowsToDescribe) override
        {
            return var ("LisBox rows");
        }
    };

    MyListBoxModel model;
    ListBox lb { "Listbox", &model };
    Label text { "Dropped", "Dropped" };

    DragAndDropTestAudioProcessor& processor;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DragAndDropTestAudioProcessorEditor)
};

ListBoxDragDrop

And here’s it working as expected in REAPER (it also successfully prevents a drag to the other window).