Switching mouse event target after clicking on Component with mouse?

I have a question about specific case of mouse dragging:

I have a Component X.
I click X with mouse and start dragging.

…at this point I want to do something a bit unusual:

  1. I want to delete the Component X completely so it doesn’t exist anymore.
  2. I want to create Component Y in its place to be dragged around the screen.

What I want to achieve with this is to make the Component Y move on screen in quantized grid, so Y jumps fixed amount of pixels at a time when the mouse moves far enough.

This would be easy to calculate if Component X was still alive. I could just read the incoming mouse event from inside X’s mouseDrag(const MouseEvent&) and update whatever needed from there. But X has been deleted and I would need those mouse events from somewhere.

Any ideas how to approach this issue?

1 Like

First question, what is the intention of swapping components?

To remove the data it is associated with so it won’t interfere with anything when the drag happens.

I’m using ValueTrees to store my data. Whenever I add/remove a child node, things happen automatically and screen gets updated automatically too. So I need to remove the associated ValueTree node while doing whatever I want to do with the dragged object.

So I remove the ValueTree node, and that also automatically destroys the Component which is visible on the screen.

Also I can select and drag several of those objects at a time. So I need to handle dragging of those Components, and their quantized locations, in some parent class anyway to make it easy to handle.

The grid Component should be handling all of this, especially since you want to drag more than one Component. But, given that, you end up running into the classic problem of mouse event ownership. if the parent is capturing the mouse events to manage dragging, then how do the children recieve events for their child Components? One solution is that you don’t have child grid Components, but instead the parent creates the individual child Components (let’s say a Label and a Button, as an example) in each grid space, but that feels so unelegant. Certainly post an update if you find the more elegant solution.

You could perhaps hide Component X (setVisible(false)), drag it around in tandem with Component Y, then delete it at the end when you’re done.

Just a shot in the dark:

Can you have a separate ValueTree structure (independent from your main GUI hierarchy) which holds all of your currently dragging Components? So when you select a Component for dragging, it removes the ValueTree from the main GUI hierarchy and adds it to the currentlyDragging ValueTree. Then you can set up listeners on currentlyDragging so that when the posX and posY properties of any of the children are updated, it updates the rest of them also. Once the dragging process is finished, you can copy the ValueTrees back to tha main GUI hierarchy.

This reminds me of the vertical bars that pop up everytime you click on a knob in Synth1. Only difference is that the knobs don’t disappear during the drag operation. I say disappear instead of delete, because I don’t think things need to function exactly like what it looks like. ComponentX’s mouseDrag could continuously setVisible(false) the component and only set it true again in mouseUp. don’t use mouseDown, or it will also happen on clicks, that are not drags! mouseDrag and mouseUp could then do the opposite thing to ComponentY which only visualizes your operation on ComponentX. if you want the drag operations to look even less related to ComponentX you can hide the cursor and set unbounded drag to true during mouseDrag. that also enables the user to drag endlessly into any direction. in mouseUp you can show the cursor again and even place it centred over where ComponentY was if it should really feel like it was just there

That’s an interesting idea, but that would have one conflict with my current implementation:

The parent of the ValueTree node is made to react to any child ValueTree changes automatically. So if I detach the ValueTree from it’s parent, the Component will be delete automatically.

So basically when I start dragging the Component and detach it from its parent and add it to a new parent, but dragged component gets deleted and a new one gets created at that point, which is actually exactly the issue I am having currently and asking about in this thread.

This idea might work. I’ll look more into it. It’s also what stephenk seemed to suggest.

Except there’s one special condition when it doesn’t work in my use:

The draggable objects are midi/audio clips in a timeline (DAW). If a middle part of a clip has been painted with mouse by the user, and that painted area is then dragged with mouse, the result should be that the painted area is split into its own clip and should also be removed from the original clip. (making the original clip into three parts: left, middle (dragged part) and right) This should be instantly visible to the user.

So new Components still would need to be created in that case. Maybe I can take that special case into account somehow. The Component which gets hidden with setVisible(false) would then always be ensured to be the part which user drags with mouse.

OK, so here’s my current plan based on all the feedback in this thread:

  1. Store into safe place pointers of those Components which start being dragged.

  2. Clone those same components and add the to the screen.

  3. Make the original components invisible on screen, but leave them there.

  4. Cut/crop/etc. the cloned Components so they reflect exactly what the user is doing to them (i.e. to the clips) so the user gets visual feedback correctly what’s going on.

  5. When the user drops the dragged Component clones, they already represent the correctly cut/cropped/etc. data. Just remove the original untouched Components (found from the list of pointers we saved earlier) and add the already correctly processed clones where ever they are dropped.

That should allow any and all possible clip editing and processing without having to worry at all if the user grabbed some specific part of the clip or not. That might actually work.