87 lines
3.1 KiB
TypeScript
87 lines
3.1 KiB
TypeScript
import { KGCommand } from '../KGCommand';
|
|
import { KGCore } from '../../KGCore';
|
|
import { GlobalTrackType } from '../../global-track';
|
|
import { KGChordRegion } from '../../region/KGChordRegion';
|
|
import { generateUniqueId } from '../../../util/miscUtil';
|
|
import { findChordRegionAtBeat, findGlobalTrackByType } from '../../../util/globalTrackUtil';
|
|
|
|
export class InsertChordRegionAtBeatCommand extends KGCommand {
|
|
private readonly insertBeat: number;
|
|
private readonly symbol: string;
|
|
private readonly regionId: string;
|
|
private createdRegion: KGChordRegion | null = null;
|
|
private targetRegionId: string | null = null;
|
|
private originalTargetLength = 0;
|
|
|
|
constructor(insertBeat: number, symbol: string = 'C', regionId?: string) {
|
|
super();
|
|
this.insertBeat = insertBeat;
|
|
this.symbol = symbol;
|
|
this.regionId = regionId ?? generateUniqueId('KGChordRegion');
|
|
}
|
|
|
|
execute(): void {
|
|
const project = KGCore.instance().getCurrentProject();
|
|
const chordTrack = findGlobalTrackByType(project, GlobalTrackType.Chord);
|
|
if (!chordTrack) {
|
|
throw new Error('Chord global track not found');
|
|
}
|
|
|
|
const occupiedRegion = findChordRegionAtBeat(project, this.insertBeat);
|
|
if (!occupiedRegion) {
|
|
throw new Error(`No chord region found at beat ${this.insertBeat}`);
|
|
}
|
|
|
|
const regionStart = occupiedRegion.getStartFromBeat();
|
|
const regionEnd = regionStart + occupiedRegion.getLength();
|
|
if (this.insertBeat <= regionStart || this.insertBeat >= regionEnd) {
|
|
throw new Error(`Cannot insert chord at beat ${this.insertBeat} without shrinking region below minimum length`);
|
|
}
|
|
|
|
this.targetRegionId = occupiedRegion.getId();
|
|
this.originalTargetLength = occupiedRegion.getLength();
|
|
occupiedRegion.setLength(this.insertBeat - regionStart);
|
|
|
|
this.createdRegion = new KGChordRegion(
|
|
this.regionId,
|
|
chordTrack.getId(),
|
|
chordTrack.getTrackIndex(),
|
|
this.symbol,
|
|
this.insertBeat,
|
|
regionEnd - this.insertBeat
|
|
);
|
|
|
|
chordTrack.setRegions(
|
|
[...chordTrack.getRegions(), this.createdRegion]
|
|
.sort((left, right) => left.getStartFromBeat() - right.getStartFromBeat())
|
|
);
|
|
}
|
|
|
|
undo(): void {
|
|
const project = KGCore.instance().getCurrentProject();
|
|
const chordTrack = findGlobalTrackByType(project, GlobalTrackType.Chord);
|
|
if (!chordTrack || !this.targetRegionId || !this.createdRegion) {
|
|
throw new Error('Cannot undo inserted chord region');
|
|
}
|
|
|
|
chordTrack.removeRegion(this.createdRegion.getId());
|
|
const targetRegion = chordTrack.getRegions().find((region): region is KGChordRegion => (
|
|
region instanceof KGChordRegion && region.getId() === this.targetRegionId
|
|
));
|
|
if (!targetRegion) {
|
|
throw new Error(`Chord region ${this.targetRegionId} not found during undo`);
|
|
}
|
|
|
|
targetRegion.setLength(this.originalTargetLength);
|
|
chordTrack.setRegions([...chordTrack.getRegions()].sort((left, right) => left.getStartFromBeat() - right.getStartFromBeat()));
|
|
}
|
|
|
|
getDescription(): string {
|
|
return `Insert chord "${this.symbol}"`;
|
|
}
|
|
|
|
public getCreatedRegion(): KGChordRegion | null {
|
|
return this.createdRegion;
|
|
}
|
|
}
|