fix: doc-level ruler drag, min 16bars playback, selection overlay, edge/center handles
This commit is contained in:
+100
-25
@@ -5739,29 +5739,32 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
|
||||
}
|
||||
return;
|
||||
}
|
||||
rulerDragRef.current = { startX: e.clientX, startBeat: clickBeat, scrollLeft: e.currentTarget.scrollLeft };
|
||||
},
|
||||
onMouseMove: e => {
|
||||
if (!rulerDragRef.current) return;
|
||||
const rect = e.currentTarget.getBoundingClientRect();
|
||||
const x = e.clientX - rect.left + rulerDragRef.current.scrollLeft;
|
||||
const beat = Math.max(0, x / pixelsPerBeat);
|
||||
if (Math.abs(e.clientX - rulerDragRef.current.startX) > 5) {
|
||||
const sBeat = Math.max(0, Math.min(rulerDragRef.current.startBeat, beat));
|
||||
const eBeat = Math.max(sBeat + 1, Math.max(rulerDragRef.current.startBeat, beat));
|
||||
setLoopStartBeat(sBeat);
|
||||
setLoopEndBeat(eBeat);
|
||||
setIsLooping(true);
|
||||
setSubTabs(prev => prev.map(s => s.id === st.id ? {
|
||||
...s,
|
||||
selectionStart: sBeat * beatSec,
|
||||
selectionEnd: eBeat * beatSec,
|
||||
isLooping: true
|
||||
} : s));
|
||||
}
|
||||
},
|
||||
onMouseUp: () => { rulerDragRef.current = null; },
|
||||
onMouseLeave: () => { rulerDragRef.current = null; }
|
||||
const startData = { startX: e.clientX, startBeat: clickBeat, scrollLeft: e.currentTarget.scrollLeft };
|
||||
rulerDragRef.current = startData;
|
||||
const onMove = (ev) => {
|
||||
const r = rulerScrollRef.current;
|
||||
if (!r || !rulerDragRef.current) return;
|
||||
const rRect = r.getBoundingClientRect();
|
||||
const bx = ev.clientX - rRect.left + rulerDragRef.current.scrollLeft;
|
||||
const beat = Math.max(0, bx / pixelsPerBeat);
|
||||
if (Math.abs(ev.clientX - rulerDragRef.current.startX) > 5) {
|
||||
const sBeat = Math.max(0, Math.min(rulerDragRef.current.startBeat, beat));
|
||||
const eBeat = Math.max(sBeat + 1, Math.max(rulerDragRef.current.startBeat, beat));
|
||||
setLoopStartBeat(sBeat);
|
||||
setLoopEndBeat(eBeat);
|
||||
setIsLooping(true);
|
||||
setSubTabs(prev => prev.map(s => s.id === st.id ? {
|
||||
...s,
|
||||
selectionStart: sBeat * beatSec,
|
||||
selectionEnd: eBeat * beatSec,
|
||||
isLooping: true
|
||||
} : s));
|
||||
}
|
||||
};
|
||||
const onUp = () => { rulerDragRef.current = null; document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp); };
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('mouseup', onUp);
|
||||
}
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
style: {
|
||||
width: `${viewWidth}px`,
|
||||
@@ -5774,7 +5777,65 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
|
||||
width: `${(loopEndBeat - loopStartBeat) * pixelsPerBeat}px`,
|
||||
top: 0, bottom: 0
|
||||
},
|
||||
className: "absolute bg-emerald-500/15 border-l border-r border-emerald-400 pointer-events-none"
|
||||
className: "absolute bg-emerald-500/15 border-l border-r border-emerald-400"
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
style: { position: 'absolute', left: 0, top: 0, bottom: 0, width: '4px', cursor: 'ew-resize' },
|
||||
onMouseDown: (e) => {
|
||||
e.stopPropagation();
|
||||
const startBeat = loopStartBeat;
|
||||
const onMove = (ev) => {
|
||||
const r = rulerScrollRef.current;
|
||||
if (!r) return;
|
||||
const rRect = r.getBoundingClientRect();
|
||||
const bx = ev.clientX - rRect.left + r.scrollLeft;
|
||||
const nBeat = Math.max(0, Math.min(loopEndBeat - 1, Math.round(bx / pixelsPerBeat / 4) * 4));
|
||||
setLoopStartBeat(nBeat);
|
||||
setSubTabs(prev => prev.map(s => s.id === st.id ? { ...s, selectionStart: nBeat * beatSec } : s));
|
||||
};
|
||||
const onUp = () => { document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp); };
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('mouseup', onUp);
|
||||
}
|
||||
}), /*#__PURE__*/React.createElement("div", {
|
||||
style: { position: 'absolute', right: 0, top: 0, bottom: 0, width: '4px', cursor: 'ew-resize' },
|
||||
onMouseDown: (e) => {
|
||||
e.stopPropagation();
|
||||
const onMove = (ev) => {
|
||||
const r = rulerScrollRef.current;
|
||||
if (!r) return;
|
||||
const rRect = r.getBoundingClientRect();
|
||||
const bx = ev.clientX - rRect.left + r.scrollLeft;
|
||||
const nBeat = Math.max(loopStartBeat + 1, Math.round(bx / pixelsPerBeat / 4) * 4);
|
||||
setLoopEndBeat(nBeat);
|
||||
setSubTabs(prev => prev.map(s => s.id === st.id ? { ...s, selectionEnd: nBeat * beatSec } : s));
|
||||
};
|
||||
const onUp = () => { document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp); };
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('mouseup', onUp);
|
||||
}
|
||||
}), /*#__PURE__*/React.createElement("div", {
|
||||
style: { position: 'absolute', left: '4px', right: '4px', top: 0, bottom: 0, cursor: 'grab' },
|
||||
onMouseDown: (e) => {
|
||||
e.stopPropagation();
|
||||
const startBeat = loopStartBeat;
|
||||
const range = loopEndBeat - loopStartBeat;
|
||||
const offsetBeat = startBeat + range / 2;
|
||||
const onMove = (ev) => {
|
||||
const r = rulerScrollRef.current;
|
||||
if (!r) return;
|
||||
const rRect = r.getBoundingClientRect();
|
||||
const bx = ev.clientX - rRect.left + r.scrollLeft;
|
||||
const centerBeat = Math.round(bx / pixelsPerBeat / 4) * 4;
|
||||
const halfRange = range / 2;
|
||||
const newStart = Math.max(0, centerBeat - halfRange);
|
||||
setLoopStartBeat(newStart);
|
||||
setLoopEndBeat(newStart + range);
|
||||
setSubTabs(prev => prev.map(s => s.id === st.id ? { ...s, selectionStart: newStart * beatSec, selectionEnd: (newStart + range) * beatSec } : s));
|
||||
};
|
||||
const onUp = () => { document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp); };
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('mouseup', onUp);
|
||||
}
|
||||
})))), /*#__PURE__*/React.createElement("div", {
|
||||
className: "flex-1 flex overflow-hidden min-h-0 relative"
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
@@ -5803,6 +5864,13 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
|
||||
onMouseLeave: handleGridMouseUp,
|
||||
onContextMenu: handleContextMenu,
|
||||
className: "absolute inset-0 cursor-crosshair"
|
||||
}), loopStartBeat !== null && loopEndBeat !== null && loopEndBeat > loopStartBeat && /*#__PURE__*/React.createElement("div", {
|
||||
style: {
|
||||
left: `${loopStartBeat * pixelsPerBeat}px`,
|
||||
width: `${(loopEndBeat - loopStartBeat) * pixelsPerBeat}px`,
|
||||
top: 0, bottom: 0
|
||||
},
|
||||
className: "absolute bg-emerald-500/10 border-l border-r border-emerald-400/50 pointer-events-none"
|
||||
})))), showCC && /*#__PURE__*/React.createElement("div", {
|
||||
style: { height: `${ccHeight}px` },
|
||||
className: "bg-[#161616] border-t border-zinc-900 flex shrink-0 relative"
|
||||
@@ -5835,6 +5903,13 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
|
||||
onMouseUp: () => { ccDragRef.current = null; },
|
||||
onMouseLeave: () => { ccDragRef.current = null; },
|
||||
className: "absolute inset-0"
|
||||
}), loopStartBeat !== null && loopEndBeat !== null && loopEndBeat > loopStartBeat && /*#__PURE__*/React.createElement("div", {
|
||||
style: {
|
||||
left: `${loopStartBeat * pixelsPerBeat}px`,
|
||||
width: `${(loopEndBeat - loopStartBeat) * pixelsPerBeat}px`,
|
||||
top: 0, bottom: 0
|
||||
},
|
||||
className: "absolute bg-emerald-500/10 border-l border-r border-emerald-400/50 pointer-events-none"
|
||||
})))), scaleMenuPos && renderScaleContextMenu());
|
||||
};
|
||||
|
||||
@@ -9304,7 +9379,7 @@ const App = () => {
|
||||
const end = (n.start_beat || 0) + (n.duration_beats || 1);
|
||||
if (end > maxEnd) maxEnd = end;
|
||||
});
|
||||
return maxEnd * beatSec + 1.0;
|
||||
return Math.max(maxEnd * beatSec, 16 * beatSec * 4) + 1.0;
|
||||
})() : st.buffer.duration;
|
||||
if (bufferPos >= effectiveDuration) {
|
||||
stopAllPlayback();
|
||||
|
||||
Reference in New Issue
Block a user