In my working C# winforms application, I’m trying to achieve the draggable control behavior where when the user drags a MidiNote control (it’s just called MidiNote rn, gonna be for different controls later) between 2 others, all of the controls to the right of it will “scoot” or slide to the right in order to make room for it (almost like inserting magnets between one another). Then conversely, if you drag a control out to say the very left end, the gap left by the moved control will collapse.
I know this control behavior has been done time and time again for other application (it’s used in Apple’s Final Cut Pro magnetic timeline for instance), but I cannot seem to wrap my head around doing it myself (at least not beyond the point I’m at now)!
Here’s an example of someone achieving this using JQuery, but I don’t think it’s logic transfers too well to c# winform controls.
So far, I’m able to with 3 controls drag them between one another, but the moment I do with 4+, the logic breaks (do I need to use recursion somewhere)?
Any help is greatly appreciated. I’d be happy it we can together boil this behavior (and similar ones) down to a generic algorithm for all to use. If you need more code or context, lmk.
Thanks!
private void PianoRoll_MouseMove(object? sender, MouseEventArgs e)
{
const int Y_POS = 200; //arbitrary
if (_bMouseDownOnNote)
{
foreach (MidiNote n in this.Controls.OfType<MidiNote>())
{
if (n != _noteToMove)
{
if (n.Bounds.Contains(new Point(e.X, Y_POS)))
{
int eX = e.X; int nRight = n.Right; int nWidth = n.Width;
if (eX > (nRight - (nWidth / 2)))
{
Point p = new Point(nRight, Y_POS);
_noteToMove.Location = p;
//k, we've moved the note, now loop all the notes to the right of this and scoot them accordingly
foreach (MidiNote n2 in this.Controls.OfType<MidiNote>())
{
if (n2 != _noteToMove && n2 != n)
{
if (n2.Bounds.Contains(new Point(x: nRight, y: Y_POS)))
{
int n2Left = n2.Left;
Point p2 = new Point(n2Left + nWidth, Y_POS);
n2.Location = p2;
nRight = n2Left + nWidth;
}
}
}
}
else if (eX < (nRight - (nWidth / 2)))
{
int nLeft = n.Left;
Point p = new Point(nLeft - nWidth, Y_POS);
_noteToMove.Location = p;
//haven't handled for multiple notes here yet :/
}
}
}
}
}
}