fix: group drag keeps items on their original tracks
Remove all cross-track logic in multiIds path. Each item only updates its time position (delta) on its current track. No merging or track reassignment.
This commit is contained in:
+24
-96
@@ -12049,119 +12049,47 @@ const App = () => {
|
||||
wrapper.scrollLeft = Math.max(0, itemPx - keepMargin);
|
||||
setCanvasRedrawCount(n => n + 1);
|
||||
}
|
||||
var allTrksNow = activeTracksRef.current || [];
|
||||
var targetTrackId = hoveredTrackIdRef.current || drag.trackId;
|
||||
// Clamp to min track 0 (first track)
|
||||
var trkIds = allTrksNow.map(function(x) { return x.id; });
|
||||
var targetIdx = trkIds.indexOf(targetTrackId);
|
||||
if (targetIdx < 0 && allTrksNow.length > 0) targetTrackId = allTrksNow[0].id;
|
||||
// Auto-add track when dragging below the last track
|
||||
if (targetIdx < 0 || targetIdx >= allTrksNow.length - 1) {
|
||||
var isBelow = e.clientY > rect.top + rect.height;
|
||||
if (isBelow) {
|
||||
addNewTrack();
|
||||
var newTrks = activeTracksRef.current || [];
|
||||
targetTrackId = newTrks[newTrks.length - 1].id;
|
||||
}
|
||||
}
|
||||
updateActiveTracks(prev => {
|
||||
let movedItem = null;
|
||||
for (let track of prev) {
|
||||
// Search all item types for the dragged item
|
||||
const sec = (track.sections || []).find(it => it.id === drag.itemId);
|
||||
const mid = (track.midiItems || []).find(it => it.id === drag.itemId);
|
||||
if (sec || mid) { movedItem = sec || mid; break; }
|
||||
}
|
||||
// Build a live map: where does each multi-drag item currently live?
|
||||
var currentTrackMap = {};
|
||||
if (drag.multiIds) {
|
||||
Object.keys(drag.multiIds).forEach(function(mid) {
|
||||
var info = drag.multiIds[mid];
|
||||
for (var pi = 0; pi < prev.length; pi++) {
|
||||
var pt = prev[pi];
|
||||
var foundHere = false;
|
||||
if (info.type === 'section') foundHere = (pt.sections || []).some(function(s) { return s.id === mid; });
|
||||
else if (info.type === 'midiItem') foundHere = (pt.midiItems || []).some(function(m) { return m.id === mid; });
|
||||
else if (info.type === 'clip') foundHere = (pt.clips || []).some(function(c) { return c.id === mid || 'default_' + pt.id === mid; });
|
||||
if (foundHere) { currentTrackMap[mid] = pt.id; break; }
|
||||
}
|
||||
});
|
||||
}
|
||||
return prev.map(t => {
|
||||
if (drag.multiIds) {
|
||||
var dragOrigStart = drag.multiIds[drag.itemId] ? drag.multiIds[drag.itemId].start : 0;
|
||||
var delta = newStart - dragOrigStart;
|
||||
var dragOrigStart = drag.multiIds[drag.itemId] ? drag.multiIds[drag.itemId].start : 0;
|
||||
var delta = newStart - dragOrigStart;
|
||||
return prev.map(t => {
|
||||
var resultSections = (t.sections || []).slice();
|
||||
var resultMidis = (t.midiItems || []).slice();
|
||||
var resultClips = (t.clips || []).slice();
|
||||
var crossTracks = targetTrackId !== drag.trackId;
|
||||
Object.keys(drag.multiIds).forEach(function(mid) {
|
||||
var info = drag.multiIds[mid];
|
||||
var newVal = info.start + delta;
|
||||
var currentTid = currentTrackMap.hasOwnProperty(mid) ? currentTrackMap[mid] : info.trackId;
|
||||
var onCurrentTrack = currentTid === t.id;
|
||||
if (onCurrentTrack) {
|
||||
if (!crossTracks || t.id === targetTrackId) {
|
||||
if (info.type === 'section') {
|
||||
var idx = resultSections.findIndex(function(s) { return s.id === mid; });
|
||||
if (idx >= 0) resultSections[idx] = { ...resultSections[idx], start: Math.max(0, newVal) };
|
||||
} else if (info.type === 'midiItem') {
|
||||
var idx = resultMidis.findIndex(function(mx) { return mx.id === mid; });
|
||||
if (idx >= 0) resultMidis[idx] = { ...resultMidis[idx], startTime: Math.max(0, newVal) };
|
||||
} else if (info.type === 'clip') {
|
||||
var idx = resultClips.findIndex(function(cx) { return cx.id === mid || 'default_' + t.id === mid; });
|
||||
if (idx >= 0) resultClips[idx] = { ...resultClips[idx], startTime: Math.max(0, newVal) };
|
||||
}
|
||||
} else {
|
||||
if (info.type === 'section') resultSections = resultSections.filter(function(s) { return s.id !== mid; });
|
||||
else if (info.type === 'midiItem') resultMidis = resultMidis.filter(function(mx) { return mx.id !== mid; });
|
||||
else if (info.type === 'clip') { var cid3 = 'default_' + t.id; resultClips = resultClips.filter(function(cx) { return cx.id !== mid && cx.id !== cid3; }); }
|
||||
}
|
||||
} else if (crossTracks && t.id === targetTrackId) {
|
||||
var srcItem = null;
|
||||
for (var pi2 = 0; pi2 < prev.length; pi2++) {
|
||||
var tr2 = prev[pi2];
|
||||
if (info.type === 'section') srcItem = (tr2.sections || []).find(function(s) { return s.id === mid; });
|
||||
else if (info.type === 'midiItem') srcItem = (tr2.midiItems || []).find(function(mx) { return mx.id === mid; });
|
||||
else if (info.type === 'clip') { var c2 = (tr2.clips || []).find(function(cx) { return cx.id === mid || 'default_' + tr2.id === mid; }); if (c2) srcItem = c2; }
|
||||
if (srcItem) break;
|
||||
}
|
||||
if (srcItem) {
|
||||
if (info.type === 'section') {
|
||||
resultSections = resultSections.filter(function(s) { return s.id !== mid; });
|
||||
resultSections.push({ ...srcItem, start: Math.max(0, newVal) });
|
||||
} else if (info.type === 'midiItem') {
|
||||
resultMidis = resultMidis.filter(function(mx) { return mx.id !== mid; });
|
||||
resultMidis.push({ ...srcItem, startTime: Math.max(0, newVal) });
|
||||
} else if (info.type === 'clip') {
|
||||
var cid4 = 'default_' + t.id;
|
||||
resultClips = resultClips.filter(function(cx) { return cx.id !== mid && cx.id !== cid4; });
|
||||
resultClips.push({ ...srcItem, startTime: Math.max(0, newVal) });
|
||||
}
|
||||
}
|
||||
if (info.type === 'section') {
|
||||
var idx = resultSections.findIndex(function(s) { return s.id === mid; });
|
||||
if (idx >= 0) resultSections[idx] = { ...resultSections[idx], start: Math.max(0, newVal) };
|
||||
} else if (info.type === 'midiItem') {
|
||||
var idx = resultMidis.findIndex(function(mx) { return mx.id === mid; });
|
||||
if (idx >= 0) resultMidis[idx] = { ...resultMidis[idx], startTime: Math.max(0, newVal) };
|
||||
} else if (info.type === 'clip') {
|
||||
var idx = resultClips.findIndex(function(cx) { return cx.id === mid || 'default_' + t.id === mid; });
|
||||
if (idx >= 0) resultClips[idx] = { ...resultClips[idx], startTime: Math.max(0, newVal) };
|
||||
}
|
||||
});
|
||||
return { ...t, sections: resultSections, midiItems: resultMidis, clips: resultClips };
|
||||
}
|
||||
const items = drag.itemType === 'section' ? (t.sections || []) : (t.midiItems || []);
|
||||
const updatedItems = items.filter(it => it.id !== drag.itemId);
|
||||
if (t.id === targetTrackId) {
|
||||
if (movedItem) {
|
||||
updatedItems.push(drag.itemType === 'section'
|
||||
? { ...movedItem, start: newStart }
|
||||
: { ...movedItem, startTime: newStart });
|
||||
} else {
|
||||
if (drag.itemType === 'section') {
|
||||
updatedItems.push({ id: drag.itemId, name: 'Section', start: newStart, duration: 4 * secondsPerBar, color: '#06b6d4' });
|
||||
} else {
|
||||
updatedItems.push({ id: drag.itemId, name: 'MIDI Item', startTime: newStart, duration: 4 * secondsPerBar, notes: [], color: '#a78bfa' });
|
||||
}
|
||||
}
|
||||
}
|
||||
return drag.itemType === 'section'
|
||||
? { ...t, sections: updatedItems }
|
||||
: { ...t, midiItems: updatedItems };
|
||||
});
|
||||
});
|
||||
}
|
||||
const items = drag.itemType === 'section' ? (t.sections || []) : (t.midiItems || []);
|
||||
const updatedItems = items.filter(it => it.id !== drag.itemId);
|
||||
if (movedItem) {
|
||||
updatedItems.push(drag.itemType === 'section'
|
||||
? { ...movedItem, start: newStart }
|
||||
: { ...movedItem, startTime: newStart });
|
||||
}
|
||||
return prev.map(t => drag.itemType === 'section'
|
||||
? { ...t, sections: updatedItems }
|
||||
: { ...t, midiItems: updatedItems });
|
||||
});
|
||||
if (drag.trackId !== targetTrackId) {
|
||||
setDraggedSectionItem(prev => ({ ...prev, trackId: targetTrackId }));
|
||||
|
||||
Reference in New Issue
Block a user