Best strategy for dragging clip selection across tracks

Hey all,

I’m developing a rudimentary DAW interface and I was wondering what the best strategy would be to implement the following dragging behaviour using JUCE:


Mainly vertical dragging across tracks is giving me a headache (horizontal I can easily do with a custom written MultiComponentDragger). Especially because all my ClipComponents live within TrackComponents, it’s not as easy as just changing their bounds; I’d have to add and remove them from parent tracks dynamically.

I also thought about using the DragAndDropTarget system for this, or even ditching TrackComponents altogether and going for some sort of multi-track clip container component without hierarchy.

I’d be very curious to hear your thoughts. I’ve been racking my brain over this for a while now and none of the solutions I came up with seem satisfactory (how does Tracktion handle this?).


You can add and remove them dynamically after your action is finally done. When dragging you can use dummy snapshots of the clips and position them along the tracks. At least I did it this way but someone can have a different approach.

I would advise against setBounds directly from mouse movement.

The position in mouseDrag sets the time and track of your clip, and that sends an update, which calls setBounds() with the proper coordinates. That is, because you need the transformation from the information from your project anyway, so you don’t want a different way calculating it from mouse movement or from programmatic change, or even undo

Thanks, that makes sense! :slight_smile: I’m gonna try this, sounds like a lot less hassle than actually move them components around during drag.

Thanks, Daniel! I forgot to mention in the original post that I’ve got a system set up where model change are automatically reflected in the view. I’d like the model to only actually change on mouse up, so that’s why I was thinking of updating the view bounds dynamically (without updating the model).

Hmmm, drawing dummies works pretty well using createComponentSnapshot(). I’m running into problems when one of the tracks has a different height than the others, though. Afaik, there’s not really a way to snapshot a component as if it had a different size.

Also seen some Tracktion Engine stuff vids lately (very impressive!), and though the engine doesn’t contain much UI code, perhaps @dave96 can shed some light on the too (I hope I’m not inconveniencing you by tagging you :sweat_smile:)?

You should write your custom snapshot method or just create a dummy copy of a clip which can be rescaled when dragging.

Dragging clips is surprisingly more complicated than it sounds as you might have to do other things like move automation etc.

What we do in Waveform is have an RAII object called DragClipsOperation which effectively takes a snapshot of the items in the list and where the mouse started the drag. Then when you move the mouse it updates the data model (position of clips etc.) based on the new mouse position.
To get automation drags correct etc. during every drag “update” you have to undo the current action so you’re always applying the “current mouse position” to the “initial state”.
I hope that makes sense.

We don’t use ghost images, we simply move the actual clips but don’t rebuild the audio graph until the drag has ended (so the new positions are not heard).
If you really want to view the ghost clips I’d probably add some kind of special property to them so their simply drawn differently in the UI and then tidy them up once the drag has ended.

Using image snapshots feels like it could be the wrong approach to me.


Hi Dave! Thanks for your reply :slight_smile:

Yes, thanks, that makes perfect sense. That’s basically how I’ve implemented multi-drag in the past before, based on JUCE’s ComponentDragger (initial state + delta based on mouse drag).

So does that mean that Waveform has all its clip views in one big component covering all track lanes? Because otherwise you’d have to dynamically remove and add them from TrackComponents.

No. I can’t see why what advantage this would bring?

Yeah, that’s what we do. It’s all handled automatically by the track views updating to reflect changes in the model.

Basically, if we handle adjusting the model correctly (via the ValueTree), the view is always correct.

Ok wait, so if I’m understanding you correctly:

  1. While dragging you’re updating the data model (which updates the view) through the ValueTree. So no direct setBounds() but actual ValueTree changes.
  2. One mouse up you actually update the audio graph.

So updating the ValueTree doesn’t necessarily equate to automatic graph changes?

Very interesting :slight_smile: I should be more specific about snapshots, I did not mean exactly image snapshots but dummy copies of clip views which can be moved and repainted freely.

Btw. there is a bug (?) in Waveform related to dragging multiple clips from more than one track. When there is a submix subtrack or folder subtrack present somewhere the clips being dragged are not placed on the correct tracks.

See the tracktion_engine::TransportControl::ReallocationInhibitor class.

The clip dragging logic in Tracktion has taken over 15 years of evolution and refactoring to get right, and judging by MBO’s post above, still isn’t 100% perfect!

But any kind of solution that involves explicitly moving components or GUI stuff is going to be way off-track. The only sensible way to do this is like Dave says: manipulate the model and let the GUI follow it.

Was perfect until subtracks arrived :wink: Being serious I discovered it today by accident although I use Waveform rather often.

@MBO Can you elaborate on the bug a little bit as I can’t seem to reproduce it.
Also, what version of Waveform are you using?

Yes. Let’s say we have:

  • Clip 1 on Track 1
  • Clip 2 on Track 2
  • Track 1 has a submix track.

When you drag both clips down, they should go to Track 2 and 3 respectively, then to Track 3 and 4 etc. Instead, Clip 1 is not moved, Clip 2 is moved to Track 3, so both clips are separated then by one track but they should not.

Waveform 10.1.4 on Mac.

Edit: If you add for example an additional folder track to Track 1 which already has a submix track then these clips will be separated by two tracks after drag etc.

Sorry, I’m still not getting this. If I have the following setup:

and then drag the clip on track 1 down, they both jump down a track, same if I drag the clip on track 2.

Maybe it’s the terminology that we’re not aligned on? I wouldn’t say “Track 1 has a submix track” in my screenshot, but “track 1 is contained within a submix track”. Or do you mean something different to the way I have it set up?


Sorry, I should say “Create a new submix track” :

So in this configuration please start dragging both clips.

Ok, I think I see what you mean. But that track in between “Track 1” and “Track 2” that you have looks like an “Automation Track” to me. I can’t see anything that looks like a Submix/Folder track in the screenshot?

Either way, I think the problem is that the automation track is being counted for track indices but you can’t actually put clips on it. So if you drag both of those clips down, they’ll still end up with one track between them. That’s probably not what most users would expect.

I’ll see if I can figure something out but it’s fairly low priority atm :wink:
Thanks for the report though!

Yes, here is an automation track (sorry, was playing around and made a wrong screenshot) but the same behaviour is when you have a folder track or a submix track. I agree it’s not something very important - I haven’t noticed it until today. I guess not so often one moves clips from different tracks, rather clips within a track or whole tracks are moved.