fix: misc UI updates and fixes
This commit is contained in:
@@ -48,7 +48,7 @@ const Toolbar: React.FC = () => {
|
|||||||
barWidthMultiplier, setBarWidthMultiplier,
|
barWidthMultiplier, setBarWidthMultiplier,
|
||||||
isLooping, toggleLoop,
|
isLooping, toggleLoop,
|
||||||
canUndo, canRedo, undoDescription, redoDescription, undo, redo,
|
canUndo, canRedo, undoDescription, redoDescription, undo, redo,
|
||||||
toggleChatBox, toggleSettings, toggleKGOnePanel, toggleListEventPanel, showKGOnePanel, showListEventPanel, showChatBox, cleanupProjectState, toggleMetronome, isMetronomeEnabled,
|
toggleChatBox, toggleSettings, toggleKGOnePanel, toggleListEventPanel, showKGOnePanel, showListEventPanel, showChatBox, showSettings, cleanupProjectState, toggleMetronome, isMetronomeEnabled,
|
||||||
isRecording, startRecording, stopRecording,
|
isRecording, startRecording, stopRecording,
|
||||||
// Piano roll state/actions
|
// Piano roll state/actions
|
||||||
showPianoRoll, setShowPianoRoll, activeRegionId, setActiveRegionId,
|
showPianoRoll, setShowPianoRoll, activeRegionId, setActiveRegionId,
|
||||||
@@ -1065,7 +1065,13 @@ const Toolbar: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button title="Import" onClick={handleImportProject}><FaUpload /></button>
|
<button title="Import" onClick={handleImportProject}><FaUpload /></button>
|
||||||
<button title="Settings" onClick={handleSettingsClick}><FaCog /></button>
|
<button
|
||||||
|
title="Settings"
|
||||||
|
className={`tool-button ${showSettings ? 'active' : ''}`}
|
||||||
|
onClick={handleSettingsClick}
|
||||||
|
>
|
||||||
|
<FaCog />
|
||||||
|
</button>
|
||||||
<div className="toolbar-separator"></div>
|
<div className="toolbar-separator"></div>
|
||||||
<button title="Undo" onClick={handleUndoClick}><FaUndo /></button>
|
<button title="Undo" onClick={handleUndoClick}><FaUndo /></button>
|
||||||
<button title="Redo" onClick={handleRedoClick}><FaRedo /></button>
|
<button title="Redo" onClick={handleRedoClick}><FaRedo /></button>
|
||||||
|
|||||||
@@ -180,6 +180,14 @@
|
|||||||
--toolbar-button-bg: #d6d6d6;
|
--toolbar-button-bg: #d6d6d6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.piano-roll-toolbar button:focus,
|
||||||
|
.piano-roll-toolbar button:focus-visible,
|
||||||
|
.piano-roll-toolbar .tool-button:focus,
|
||||||
|
.piano-roll-toolbar .tool-button:focus-visible {
|
||||||
|
outline: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* Override pointer-events for piano roll toolbar sections */
|
/* Override pointer-events for piano roll toolbar sections */
|
||||||
.piano-roll-toolbar .toolbar-left,
|
.piano-roll-toolbar .toolbar-left,
|
||||||
.piano-roll-toolbar .toolbar-right {
|
.piano-roll-toolbar .toolbar-right {
|
||||||
@@ -310,8 +318,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-x: auto;
|
overflow: hidden;
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.piano-roll-main-section {
|
.piano-roll-main-section {
|
||||||
@@ -319,7 +326,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
min-width: calc(var(--max-number-of-bars) * var(--region-grid-bar-width) + var(--region-piano-key-width));
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.piano-roll-main-section.with-automation {
|
.piano-roll-main-section.with-automation {
|
||||||
@@ -329,34 +336,12 @@
|
|||||||
.piano-roll-note-scroll {
|
.piano-roll-note-scroll {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow-y: auto;
|
overflow: auto;
|
||||||
overflow-x: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
.piano-roll-body-shell {
|
|
||||||
display: flex;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.piano-roll-keys-viewport {
|
|
||||||
position: sticky;
|
|
||||||
left: 0;
|
|
||||||
z-index: 15;
|
|
||||||
width: var(--region-piano-key-width);
|
|
||||||
flex: 0 0 var(--region-piano-key-width);
|
|
||||||
overflow: hidden;
|
|
||||||
border-right: 1px solid #3a3a3a;
|
|
||||||
background-color: #252525;
|
|
||||||
}
|
|
||||||
|
|
||||||
.piano-roll-keys-offset {
|
|
||||||
will-change: transform;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.piano-roll-automation-section {
|
.piano-roll-automation-section {
|
||||||
flex: 0 0 50%;
|
flex: 0 0 50%;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
min-width: calc(var(--max-number-of-bars) * var(--region-grid-bar-width) + var(--region-piano-key-width));
|
|
||||||
border-top: 1px solid #3a3a3a;
|
border-top: 1px solid #3a3a3a;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -416,7 +401,11 @@
|
|||||||
width: var(--region-piano-key-width);
|
width: var(--region-piano-key-width);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
border-right: 1px solid #3a3a3a;
|
||||||
background-color: #252525;
|
background-color: #252525;
|
||||||
|
position: sticky;
|
||||||
|
left: 0;
|
||||||
|
z-index: 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
.piano-grid-container {
|
.piano-grid-container {
|
||||||
@@ -523,6 +512,13 @@
|
|||||||
min-width: calc(var(--max-number-of-bars) * var(--region-grid-bar-width) + var(--region-piano-key-width));
|
min-width: calc(var(--max-number-of-bars) * var(--region-grid-bar-width) + var(--region-piano-key-width));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.piano-roll-automation-scroll-layer {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
will-change: transform;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.piano-roll-automation-track::before {
|
.piano-roll-automation-track::before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -540,6 +536,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: var(--region-piano-key-width);
|
width: var(--region-piano-key-width);
|
||||||
background: linear-gradient(180deg, #343434 0%, #2e2e2e 100%);
|
background: linear-gradient(180deg, #343434 0%, #2e2e2e 100%);
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.piano-roll-automation-grid {
|
.piano-roll-automation-grid {
|
||||||
@@ -561,7 +558,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 8px;
|
top: 8px;
|
||||||
left: 10px;
|
left: 10px;
|
||||||
z-index: 1;
|
z-index: 3;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
|
|||||||
@@ -671,7 +671,7 @@ const PianoRoll: React.FC<PianoRollProps> = ({
|
|||||||
const handleZoomChange = useCallback((nextZoom: number) => {
|
const handleZoomChange = useCallback((nextZoom: number) => {
|
||||||
if (nextZoom === pianoRollZoom) return;
|
if (nextZoom === pianoRollZoom) return;
|
||||||
|
|
||||||
const container = pianoRollContentRef.current;
|
const container = pianoRollNoteScrollRef.current;
|
||||||
pendingZoomAnchorBeatRef.current = null;
|
pendingZoomAnchorBeatRef.current = null;
|
||||||
if (container) {
|
if (container) {
|
||||||
const keysWidth = parseInt(
|
const keysWidth = parseInt(
|
||||||
@@ -742,7 +742,7 @@ const PianoRoll: React.FC<PianoRollProps> = ({
|
|||||||
|
|
||||||
// Detect manual horizontal scroll during playback
|
// Detect manual horizontal scroll during playback
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const container = pianoRollContentRef.current;
|
const container = pianoRollNoteScrollRef.current;
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
@@ -761,7 +761,7 @@ const PianoRoll: React.FC<PianoRollProps> = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isPlaying || !autoScrollEnabled) return;
|
if (!isPlaying || !autoScrollEnabled) return;
|
||||||
|
|
||||||
const container = pianoRollContentRef.current;
|
const container = pianoRollNoteScrollRef.current;
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
const beatWidth = parseInt(
|
const beatWidth = parseInt(
|
||||||
@@ -787,7 +787,7 @@ const PianoRoll: React.FC<PianoRollProps> = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (pianoRollScrollRequest === null) return;
|
if (pianoRollScrollRequest === null) return;
|
||||||
|
|
||||||
const container = pianoRollContentRef.current;
|
const container = pianoRollNoteScrollRef.current;
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
const beatWidth = parseInt(
|
const beatWidth = parseInt(
|
||||||
@@ -820,7 +820,7 @@ const PianoRoll: React.FC<PianoRollProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const anchorBeat = pendingZoomAnchorBeatRef.current;
|
const anchorBeat = pendingZoomAnchorBeatRef.current;
|
||||||
const container = pianoRollContentRef.current;
|
const container = pianoRollNoteScrollRef.current;
|
||||||
if (anchorBeat !== null && container) {
|
if (anchorBeat !== null && container) {
|
||||||
const keysWidth = parseInt(
|
const keysWidth = parseInt(
|
||||||
getComputedStyle(document.documentElement).getPropertyValue('--region-piano-key-width')
|
getComputedStyle(document.documentElement).getPropertyValue('--region-piano-key-width')
|
||||||
@@ -845,7 +845,7 @@ const PianoRoll: React.FC<PianoRollProps> = ({
|
|||||||
|
|
||||||
// Scroll horizontally to the active region's starting bar
|
// Scroll horizontally to the active region's starting bar
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (pianoRollContentRef.current && activeRegion) {
|
if (pianoRollNoteScrollRef.current && activeRegion) {
|
||||||
// Get the starting beat of the region
|
// Get the starting beat of the region
|
||||||
const startBeat = activeRegion.getStartFromBeat();
|
const startBeat = activeRegion.getStartFromBeat();
|
||||||
|
|
||||||
@@ -866,7 +866,7 @@ const PianoRoll: React.FC<PianoRollProps> = ({
|
|||||||
const scrollPosition = barNumber * barWidth;
|
const scrollPosition = barNumber * barWidth;
|
||||||
|
|
||||||
// Scroll to the calculated position
|
// Scroll to the calculated position
|
||||||
pianoRollContentRef.current.scrollLeft = Math.max(0, scrollPosition);
|
pianoRollNoteScrollRef.current.scrollLeft = Math.max(0, scrollPosition);
|
||||||
}
|
}
|
||||||
}, [activeRegion, timeSignature]);
|
}, [activeRegion, timeSignature]);
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ interface PianoRollAutomationLaneProps {
|
|||||||
timeSignature: { numerator: number; denominator: number };
|
timeSignature: { numerator: number; denominator: number };
|
||||||
bpm?: number;
|
bpm?: number;
|
||||||
redrawVersion?: number;
|
redrawVersion?: number;
|
||||||
|
horizontalScrollLeft?: number;
|
||||||
|
onHorizontalWheel?: (delta: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AUTOMATION_COLOR = '#87CEFA';
|
const AUTOMATION_COLOR = '#87CEFA';
|
||||||
@@ -38,6 +40,8 @@ const PianoRollAutomationLane: React.FC<PianoRollAutomationLaneProps> = ({
|
|||||||
maxBars,
|
maxBars,
|
||||||
timeSignature,
|
timeSignature,
|
||||||
redrawVersion = 0,
|
redrawVersion = 0,
|
||||||
|
horizontalScrollLeft = 0,
|
||||||
|
onHorizontalWheel,
|
||||||
}) => {
|
}) => {
|
||||||
const laneRef = useRef<HTMLDivElement | null>(null);
|
const laneRef = useRef<HTMLDivElement | null>(null);
|
||||||
const [laneHeight, setLaneHeight] = useState(MIN_LANE_HEIGHT);
|
const [laneHeight, setLaneHeight] = useState(MIN_LANE_HEIGHT);
|
||||||
@@ -66,6 +70,28 @@ const PianoRollAutomationLane: React.FC<PianoRollAutomationLaneProps> = ({
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const element = laneRef.current;
|
||||||
|
if (!element) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleWheel = (event: WheelEvent) => {
|
||||||
|
const horizontalDelta = Math.abs(event.deltaX) > 0 ? event.deltaX : (event.shiftKey ? event.deltaY : 0);
|
||||||
|
if (horizontalDelta === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
onHorizontalWheel?.(horizontalDelta);
|
||||||
|
};
|
||||||
|
|
||||||
|
element.addEventListener('wheel', handleWheel, { passive: false });
|
||||||
|
return () => {
|
||||||
|
element.removeEventListener('wheel', handleWheel);
|
||||||
|
};
|
||||||
|
}, [onHorizontalWheel]);
|
||||||
|
|
||||||
const points = useMemo<AutomationPoint[]>(() => {
|
const points = useMemo<AutomationPoint[]>(() => {
|
||||||
if (!activeRegion) {
|
if (!activeRegion) {
|
||||||
return [];
|
return [];
|
||||||
@@ -160,62 +186,67 @@ const PianoRollAutomationLane: React.FC<PianoRollAutomationLaneProps> = ({
|
|||||||
>
|
>
|
||||||
<div className="piano-roll-automation-track" style={{ width: totalWidth }}>
|
<div className="piano-roll-automation-track" style={{ width: totalWidth }}>
|
||||||
<div className="piano-roll-automation-gutter" />
|
<div className="piano-roll-automation-gutter" />
|
||||||
<div className="piano-roll-automation-grid" />
|
|
||||||
<div className="piano-roll-automation-lane-label">{laneLabel}</div>
|
<div className="piano-roll-automation-lane-label">{laneLabel}</div>
|
||||||
<svg
|
<div
|
||||||
className="piano-roll-automation-svg"
|
className="piano-roll-automation-scroll-layer"
|
||||||
width="100%"
|
style={{ transform: `translateX(-${horizontalScrollLeft}px)` }}
|
||||||
height={laneHeight}
|
|
||||||
viewBox={`0 0 ${beatWidth * totalBeats + keyWidth} ${laneHeight}`}
|
|
||||||
preserveAspectRatio="none"
|
|
||||||
>
|
>
|
||||||
{interpolationMode === 'linear' && points.length > 0 && (
|
<div className="piano-roll-automation-grid" />
|
||||||
<polyline
|
<svg
|
||||||
className="piano-roll-automation-line"
|
className="piano-roll-automation-svg"
|
||||||
fill="none"
|
width="100%"
|
||||||
stroke={AUTOMATION_COLOR}
|
height={laneHeight}
|
||||||
strokeWidth="2"
|
viewBox={`0 0 ${beatWidth * totalBeats + keyWidth} ${laneHeight}`}
|
||||||
points={polylinePoints}
|
preserveAspectRatio="none"
|
||||||
/>
|
>
|
||||||
)}
|
{interpolationMode === 'linear' && points.length > 0 && (
|
||||||
{interpolationMode === 'step' && stepSegments.map(segment => (
|
<polyline
|
||||||
<line
|
className="piano-roll-automation-line"
|
||||||
key={segment.id}
|
fill="none"
|
||||||
className="piano-roll-automation-line"
|
stroke={AUTOMATION_COLOR}
|
||||||
x1={segment.x1}
|
strokeWidth="2"
|
||||||
y1={segment.y1}
|
points={polylinePoints}
|
||||||
x2={segment.x2}
|
/>
|
||||||
y2={segment.y1}
|
)}
|
||||||
stroke={AUTOMATION_COLOR}
|
{interpolationMode === 'step' && stepSegments.map(segment => (
|
||||||
strokeWidth="2"
|
<line
|
||||||
/>
|
key={segment.id}
|
||||||
))}
|
className="piano-roll-automation-line"
|
||||||
{svgPoints.map(point => {
|
x1={segment.x1}
|
||||||
const labelY = Math.max(14, Math.min(laneHeight - 6, point.y - 10));
|
y1={segment.y1}
|
||||||
|
x2={segment.x2}
|
||||||
|
y2={segment.y1}
|
||||||
|
stroke={AUTOMATION_COLOR}
|
||||||
|
strokeWidth="2"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{svgPoints.map(point => {
|
||||||
|
const labelY = Math.max(14, Math.min(laneHeight - 6, point.y - 10));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g key={point.id}>
|
<g key={point.id}>
|
||||||
<circle
|
<circle
|
||||||
className="piano-roll-automation-point"
|
className="piano-roll-automation-point"
|
||||||
cx={point.x}
|
cx={point.x}
|
||||||
cy={point.y}
|
cy={point.y}
|
||||||
r="5"
|
r="5"
|
||||||
fill={AUTOMATION_COLOR}
|
fill={AUTOMATION_COLOR}
|
||||||
stroke="#1d2428"
|
stroke="#1d2428"
|
||||||
strokeWidth="2"
|
strokeWidth="2"
|
||||||
/>
|
/>
|
||||||
<text
|
<text
|
||||||
className="piano-roll-automation-value"
|
className="piano-roll-automation-value"
|
||||||
x={point.x + 6}
|
x={point.x + 6}
|
||||||
y={labelY}
|
y={labelY}
|
||||||
fill={AUTOMATION_COLOR}
|
fill={AUTOMATION_COLOR}
|
||||||
>
|
>
|
||||||
{point.label}
|
{point.label}
|
||||||
</text>
|
</text>
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</svg>
|
</svg>
|
||||||
|
</div>
|
||||||
{points.length === 0 && (
|
{points.length === 0 && (
|
||||||
<div className="piano-roll-automation-empty-state">
|
<div className="piano-roll-automation-empty-state">
|
||||||
No {laneLabel} events in this region
|
No {laneLabel} events in this region
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ const PianoRollContent: React.FC<PianoRollContentProps> = ({
|
|||||||
const isSpectrogram = mode === 'spectrogram';
|
const isSpectrogram = mode === 'spectrogram';
|
||||||
const showAutomationLane = automationEnabled && !isSpectrogram;
|
const showAutomationLane = automationEnabled && !isSpectrogram;
|
||||||
const [spectrogramLoading, setSpectrogramLoading] = useState(false);
|
const [spectrogramLoading, setSpectrogramLoading] = useState(false);
|
||||||
const [noteScrollTop, setNoteScrollTop] = useState(0);
|
const [noteScrollLeft, setNoteScrollLeft] = useState(0);
|
||||||
const handleSpectrogramLoadingChange = useCallback((loading: boolean) => {
|
const handleSpectrogramLoadingChange = useCallback((loading: boolean) => {
|
||||||
setSpectrogramLoading(loading);
|
setSpectrogramLoading(loading);
|
||||||
}, []);
|
}, []);
|
||||||
@@ -87,6 +87,15 @@ const PianoRollContent: React.FC<PianoRollContentProps> = ({
|
|||||||
// Recording state
|
// Recording state
|
||||||
const isRecording = useProjectStore(s => s.isRecording);
|
const isRecording = useProjectStore(s => s.isRecording);
|
||||||
const recordingNotes = useProjectStore(s => s.recordingNotes);
|
const recordingNotes = useProjectStore(s => s.recordingNotes);
|
||||||
|
const forwardAutomationHorizontalWheel = useCallback((delta: number) => {
|
||||||
|
const container = noteScrollRef.current;
|
||||||
|
if (!container) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
container.scrollLeft += delta;
|
||||||
|
setNoteScrollLeft(container.scrollLeft);
|
||||||
|
}, [noteScrollRef]);
|
||||||
|
|
||||||
// Use the note operations hook for resize and drag functionality
|
// Use the note operations hook for resize and drag functionality
|
||||||
const {
|
const {
|
||||||
@@ -290,23 +299,14 @@ const PianoRollContent: React.FC<PianoRollContentProps> = ({
|
|||||||
data-testid={showAutomationLane ? 'piano-roll-content-split' : 'piano-roll-content-single'}
|
data-testid={showAutomationLane ? 'piano-roll-content-split' : 'piano-roll-content-single'}
|
||||||
>
|
>
|
||||||
<div className={`piano-roll-main-section ${showAutomationLane ? 'with-automation' : ''}`}>
|
<div className={`piano-roll-main-section ${showAutomationLane ? 'with-automation' : ''}`}>
|
||||||
<PianoGridHeader maxBars={maxBars} timeSignature={timeSignature} />
|
<div
|
||||||
|
className="piano-roll-note-scroll"
|
||||||
<div className="piano-roll-body-shell">
|
ref={noteScrollRef}
|
||||||
<div className="piano-roll-keys-viewport">
|
onScroll={(event) => setNoteScrollLeft(event.currentTarget.scrollLeft)}
|
||||||
<div
|
>
|
||||||
className="piano-roll-keys-offset"
|
<PianoGridHeader maxBars={maxBars} timeSignature={timeSignature} />
|
||||||
style={{ transform: `translateY(-${noteScrollTop}px)` }}
|
<div className="piano-roll-body">
|
||||||
>
|
<PianoKeys activeRegion={activeRegion} />
|
||||||
<PianoKeys activeRegion={activeRegion} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="piano-roll-note-scroll"
|
|
||||||
ref={noteScrollRef}
|
|
||||||
onScroll={(event) => setNoteScrollTop(event.currentTarget.scrollTop)}
|
|
||||||
>
|
|
||||||
<div className="piano-roll-body">
|
|
||||||
<PianoGrid
|
<PianoGrid
|
||||||
gridRef={pianoGridRef}
|
gridRef={pianoGridRef}
|
||||||
onDoubleClick={isSpectrogram ? () => {} : handleGridDoubleClick}
|
onDoubleClick={isSpectrogram ? () => {} : handleGridDoubleClick}
|
||||||
@@ -331,7 +331,6 @@ const PianoRollContent: React.FC<PianoRollContentProps> = ({
|
|||||||
{memoizedNotes}
|
{memoizedNotes}
|
||||||
{!isSpectrogram && recordingNoteOverlays}
|
{!isSpectrogram && recordingNoteOverlays}
|
||||||
</PianoGrid>
|
</PianoGrid>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -344,6 +343,8 @@ const PianoRollContent: React.FC<PianoRollContentProps> = ({
|
|||||||
timeSignature={timeSignature}
|
timeSignature={timeSignature}
|
||||||
bpm={bpm}
|
bpm={bpm}
|
||||||
redrawVersion={automationRedrawVersion}
|
redrawVersion={automationRedrawVersion}
|
||||||
|
horizontalScrollLeft={noteScrollLeft}
|
||||||
|
onHorizontalWheel={forwardAutomationHorizontalWheel}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -50,6 +50,12 @@ button {
|
|||||||
transition: border-color 0.25s;
|
transition: border-color 0.25s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button:focus,
|
||||||
|
button:focus-visible {
|
||||||
|
outline: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|||||||
Reference in New Issue
Block a user