Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | import React, { memo, useCallback } from "react"; import { PatternChannelNotes } from "./PatternChannelNotes"; import { PianoRollCrosshair } from "./PianoRollCrosshair"; import { StyledPianoRollPatternBlockGrid, StyledPianoRollPatternBlock, } from "./style"; import { useAppDispatch, useAppSelector } from "store/hooks"; import trackerActions from "store/features/tracker/trackerActions"; interface PianoRollPatternBlockProps { sequenceId: number; displayChannels: number[]; isDragging: boolean; playing: boolean; selectedChannel: number; } const areNumberSetsEqual = (a: Set<number>, b: Set<number>): boolean => { Iif (a === b) { return true; } Iif (a.size !== b.size) { return false; } for (const value of a) { Iif (!b.has(value)) { return false; } } return true; }; export const PianoRollPatternBlock = memo( ({ sequenceId, displayChannels, isDragging, playing, selectedChannel, }: PianoRollPatternBlockProps) => { const dispatch = useAppDispatch(); const sequence = useAppSelector( (state) => state.trackerDocument.present.song?.sequence[sequenceId], ); const isSequenceHovered = useAppSelector( (state) => state.tracker.hoverSequence === sequenceId || (state.tracker.hoverSequence === null && sequenceId === 0), ); const isFiltered = useAppSelector((state) => { const loopSequenceId = state.tracker.loopSequenceId; return loopSequenceId !== undefined && loopSequenceId !== sequenceId; }); const selectedRows = useAppSelector<Set<number>>((state) => { const rows = new Set<number>(); for (const cell of state.tracker.selectedPatternCells) { Iif ( cell.sequenceId === sequenceId && cell.channelId === selectedChannel ) { rows.add(cell.rowId); } } return rows; }, areNumberSetsEqual); const onPointerDown = useCallback(() => { Iif (isFiltered) { dispatch(trackerActions.setLoopSequenceId(undefined)); } }, [dispatch, isFiltered]); Iif (!sequence) { return null; } return ( <StyledPianoRollPatternBlock $hovered={isSequenceHovered} $isPlaying={playing} $isFiltered={isFiltered} onPointerDown={onPointerDown} > <StyledPianoRollPatternBlockGrid $size="sharp" /> <StyledPianoRollPatternBlockGrid $size="small" /> <StyledPianoRollPatternBlockGrid $size="medium" /> <StyledPianoRollPatternBlockGrid $size="large" /> <PianoRollCrosshair isSequenceHovered={isSequenceHovered} /> {displayChannels.map((channelId) => ( <PatternChannelNotes key={channelId} patternId={sequence.channels[channelId]} channelId={channelId} isActive={selectedChannel === channelId} selectedRowIds={ selectedChannel === channelId ? selectedRows : undefined } isDragging={isDragging} /> ))} </StyledPianoRollPatternBlock> ); }, ); |