Drag drop on layered components


#1

I have a situation where I have several layers of a component (which is a DragAndDropTarget). Not all of the layers are interested in all drop sources, but I noticed that it is only the top layer that gets asked the isInterestedInDragSource question. If I answer “false” I’d expect the rest of the DragAndDropTarget beneath (in z-order) to be asked, but this does not happen.

Should I work-around this, or is this perhaps not the way it was meant to be?

TIA
/R


#2

Another problem with my application: I have component A (which is a DragAndDropTarget), and a component B which is a child component of A (occupying the same area). If I set setInterceptsMouseClicks(false, true) on component B, component A stops receiving isInterestedInDragSource notifications in a drag/drop operation. This seems odd to me. Intuitively, all components in z-order should be queried…

TIA
/R


#3

Hmm - you’re right, it should recursively ask the parent comps if they’re interested. How about this tweak to juce_DragAndDropContainer.cpp:

[code] DragAndDropTarget* findTarget (const int screenX, const int screenY,
int& relX, int& relY)
{
Component* hit = getParentComponent();

    if (hit == 0)
    {
        hit = Desktop::getInstance().findComponentAt (screenX, screenY);
    }
    else
    {
        int rx = screenX, ry = screenY;
        hit->globalPositionToRelative (rx, ry);
        hit = hit->getComponentAt (rx, ry);
    }

    while (hit != 0)
    {
        DragAndDropTarget* const ddt = dynamic_cast <DragAndDropTarget*> (hit);

        if (ddt != 0)
        {
            relX = screenX;
            relY = screenY;
            hit->globalPositionToRelative (relX, relY);

            if (ddt->isInterestedInDragSource (dragDesc))
                return ddt;
        }

        hit = hit->getParentComponent();
    }

    return 0;
}[/code]

It does use the normal hit-testing mechanism to decide which component the mouse is over, so if you’ve turned off mouse interception, that comp wouldn’t be able to get dropped-on. It has to work this way in case there are funny-shaped components with odd hit-test regions.


#4

I guess that is better, however have not tested it yet. But it still won’t handle situations where sibling components are overlapped (and deriving from DragAndDropTarget). What would be nice is a Component function that returns a set of Components which all intersect a point at x, y then use that set in the findTarget function. I know it might be tricky since more than one DDT might be interested. Maybe set a jassert for that?

/R


#5

Ok, I see your point. I’ll have a think about that.


#6

With a tweak in the application design, your fix will do nicely. I’ve changed DragAndDropContainer::findTarget to:

    DragAndDropTarget* findTarget (const int screenX, const int screenY,
                                   int& relX, int& relY)
    {
        Component* hit = getParentComponent();

        if (hit == 0)
        {
            hit = Desktop::getInstance().findComponentAt (screenX, screenY);
        }
        else
        {
            int rx = screenX, ry = screenY;
            hit->globalPositionToRelative (rx, ry);
            hit = hit->getComponentAt (rx, ry);
        }

        while (hit != 0)
        {
            DragAndDropTarget* const ddt = dynamic_cast <DragAndDropTarget*> (hit);

            if (ddt != 0 && ddt->isInterestedInDragSource(dragDesc))
            {
                relX = screenX;
                relY = screenY;
                hit->globalPositionToRelative (relX, relY);
                return ddt;
            }

            hit = hit->getParentComponent();
        }

        return 0;
    }

If you could incorporate that in 1.43 would be really great.

TIA
/R


#7

Isn’t that exactly the same as my code, but very slightly more efficient?


#8

Yes. Emphasis on “more efficient”… :wink:


#9

Continuing on the “efficiency” note, since the findTarget method will report a DDT that is interested in the drag source, the calls to isInterestedInSource could be omitted in updateLocation. Though this would exclude more advanced DDTs that would allow drag/drop in a certain location within it… :?


#10

Yeah, I have a few comps that use location-based testing to see if it’s interested, so that’d break stuff. It’s not really worth optimising anyway, I’d have thought.


#11