Skip to content

Commit

Permalink
feat: [project-sequencer-statemachine] ツールに対応 (#2517)
Browse files Browse the repository at this point in the history
  • Loading branch information
sigprogramming authored Feb 2, 2025
1 parent 8c26457 commit fce6ce8
Show file tree
Hide file tree
Showing 13 changed files with 282 additions and 58 deletions.
27 changes: 26 additions & 1 deletion src/sing/sequencerStateMachine/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,36 @@ export type PartialStore = {

export type Context = ComputedRefs & Refs & { readonly store: PartialStore };

export type IdleStateId =
| "selectNotesToolIdle"
| "editNotesToolIdle"
| "drawPitchToolIdle"
| "erasePitchToolIdle";

export type SequencerStateDefinitions = StateDefinitions<
[
{
id: "idle";
id: "selectNotesToolIdle";
factoryArgs: undefined;
},
{
id: "editNotesToolIdle";
factoryArgs: undefined;
},
{
id: "drawPitchToolIdle";
factoryArgs: undefined;
},
{
id: "erasePitchToolIdle";
factoryArgs: undefined;
},
{
id: "addNote";
factoryArgs: {
cursorPosAtStart: PositionOnSequencer;
targetTrackId: TrackId;
returnStateId: IdleStateId;
};
},
{
Expand All @@ -106,6 +125,7 @@ export type SequencerStateDefinitions = StateDefinitions<
targetTrackId: TrackId;
targetNoteIds: Set<NoteId>;
mouseDownNoteId: NoteId;
returnStateId: IdleStateId;
};
},
{
Expand All @@ -115,6 +135,7 @@ export type SequencerStateDefinitions = StateDefinitions<
targetTrackId: TrackId;
targetNoteIds: Set<NoteId>;
mouseDownNoteId: NoteId;
returnStateId: IdleStateId;
};
},
{
Expand All @@ -124,26 +145,30 @@ export type SequencerStateDefinitions = StateDefinitions<
targetTrackId: TrackId;
targetNoteIds: Set<NoteId>;
mouseDownNoteId: NoteId;
returnStateId: IdleStateId;
};
},
{
id: "selectNotesWithRect";
factoryArgs: {
cursorPosAtStart: PositionOnSequencer;
returnStateId: IdleStateId;
};
},
{
id: "drawPitch";
factoryArgs: {
cursorPosAtStart: PositionOnSequencer;
targetTrackId: TrackId;
returnStateId: IdleStateId;
};
},
{
id: "erasePitch";
factoryArgs: {
cursorPosAtStart: PositionOnSequencer;
targetTrackId: TrackId;
returnStateId: IdleStateId;
};
},
]
Expand Down
12 changes: 9 additions & 3 deletions src/sing/sequencerStateMachine/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import {
} from "@/sing/sequencerStateMachine/common";
import { StateMachine } from "@/sing/stateMachine";

import { IdleState } from "@/sing/sequencerStateMachine/states/idleState";
import { SelectNotesToolIdleState } from "@/sing/sequencerStateMachine/states/selectNotesToolIdleState";
import { EditNotesToolIdleState } from "@/sing/sequencerStateMachine/states/editNotesToolIdleState";
import { DrawPitchToolIdleState } from "@/sing/sequencerStateMachine/states/drawPitchToolIdleState";
import { ErasePitchToolIdleState } from "@/sing/sequencerStateMachine/states/erasePitchToolIdleState";
import { AddNoteState } from "@/sing/sequencerStateMachine/states/addNoteState";
import { MoveNoteState } from "@/sing/sequencerStateMachine/states/moveNoteState";
import { ResizeNoteLeftState } from "@/sing/sequencerStateMachine/states/resizeNoteLeftState";
Expand All @@ -17,7 +20,10 @@ import { ErasePitchState } from "@/sing/sequencerStateMachine/states/erasePitchS
export const createSequencerStateMachine = (context: Context) => {
return new StateMachine<SequencerStateDefinitions, Input, Context>(
{
idle: () => new IdleState(),
selectNotesToolIdle: () => new SelectNotesToolIdleState(),
editNotesToolIdle: () => new EditNotesToolIdleState(),
drawPitchToolIdle: () => new DrawPitchToolIdleState(),
erasePitchToolIdle: () => new ErasePitchToolIdleState(),
addNote: (args) => new AddNoteState(args),
moveNote: (args) => new MoveNoteState(args),
resizeNoteLeft: (args) => new ResizeNoteLeftState(args),
Expand All @@ -26,7 +32,7 @@ export const createSequencerStateMachine = (context: Context) => {
drawPitch: (args) => new DrawPitchState(args),
erasePitch: (args) => new ErasePitchState(args),
},
new IdleState(),
new SelectNotesToolIdleState(),
context,
);
};
6 changes: 5 additions & 1 deletion src/sing/sequencerStateMachine/states/addNoteState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { SetNextState, State } from "@/sing/stateMachine";
import {
Context,
getGuideLineTicks,
IdleStateId,
Input,
PositionOnSequencer,
SequencerStateDefinitions,
Expand All @@ -22,6 +23,7 @@ export class AddNoteState

private readonly cursorPosAtStart: PositionOnSequencer;
private readonly targetTrackId: TrackId;
private readonly returnStateId: IdleStateId;

private currentCursorPos: PositionOnSequencer;
private innerContext:
Expand All @@ -35,9 +37,11 @@ export class AddNoteState
constructor(args: {
cursorPosAtStart: PositionOnSequencer;
targetTrackId: TrackId;
returnStateId: IdleStateId;
}) {
this.cursorPosAtStart = args.cursorPosAtStart;
this.targetTrackId = args.targetTrackId;
this.returnStateId = args.returnStateId;

this.currentCursorPos = args.cursorPosAtStart;
}
Expand Down Expand Up @@ -119,7 +123,7 @@ export class AddNoteState
this.innerContext.executePreviewProcess = true;
} else if (input.mouseEvent.type === "mouseup") {
if (mouseButton === "LEFT_BUTTON") {
setNextState("idle", undefined);
setNextState(this.returnStateId, undefined);
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/sing/sequencerStateMachine/states/drawPitchState.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SetNextState, State } from "@/sing/stateMachine";
import {
Context,
IdleStateId,
Input,
PositionOnSequencer,
SequencerStateDefinitions,
Expand All @@ -20,6 +21,7 @@ export class DrawPitchState

private readonly cursorPosAtStart: PositionOnSequencer;
private readonly targetTrackId: TrackId;
private readonly returnStateId: IdleStateId;

private currentCursorPos: PositionOnSequencer;

Expand All @@ -34,9 +36,11 @@ export class DrawPitchState
constructor(args: {
cursorPosAtStart: PositionOnSequencer;
targetTrackId: TrackId;
returnStateId: IdleStateId;
}) {
this.cursorPosAtStart = args.cursorPosAtStart;
this.targetTrackId = args.targetTrackId;
this.returnStateId = args.returnStateId;

this.currentCursorPos = args.cursorPosAtStart;
}
Expand Down Expand Up @@ -158,7 +162,7 @@ export class DrawPitchState
this.innerContext.executePreviewProcess = true;
} else if (input.mouseEvent.type === "mouseup") {
if (mouseButton === "LEFT_BUTTON") {
setNextState("idle", undefined);
setNextState(this.returnStateId, undefined);
}
}
}
Expand Down
51 changes: 51 additions & 0 deletions src/sing/sequencerStateMachine/states/drawPitchToolIdleState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { SetNextState, State } from "@/sing/stateMachine";
import {
Context,
Input,
SequencerStateDefinitions,
} from "@/sing/sequencerStateMachine/common";
import { getButton } from "@/sing/viewHelper";
import { isOnCommandOrCtrlKeyDown } from "@/store/utility";

export class DrawPitchToolIdleState
implements State<SequencerStateDefinitions, Input, Context>
{
readonly id = "drawPitchToolIdle";

onEnter() {}

process({
input,
context,
setNextState,
}: {
input: Input;
context: Context;
setNextState: SetNextState<SequencerStateDefinitions>;
}) {
const mouseButton = getButton(input.mouseEvent);
const selectedTrackId = context.selectedTrackId.value;

if (
input.mouseEvent.type === "mousedown" &&
mouseButton === "LEFT_BUTTON" &&
input.targetArea === "SequencerBody"
) {
if (isOnCommandOrCtrlKeyDown(input.mouseEvent)) {
setNextState("erasePitch", {
cursorPosAtStart: input.cursorPos,
targetTrackId: selectedTrackId,
returnStateId: this.id,
});
} else {
setNextState("drawPitch", {
cursorPosAtStart: input.cursorPos,
targetTrackId: selectedTrackId,
returnStateId: this.id,
});
}
}
}

onExit() {}
}
91 changes: 91 additions & 0 deletions src/sing/sequencerStateMachine/states/editNotesToolIdleState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { SetNextState, State } from "@/sing/stateMachine";
import {
Context,
executeNotesSelectionProcess,
getGuideLineTicks,
Input,
SequencerStateDefinitions,
} from "@/sing/sequencerStateMachine/common";
import { getButton, isSelfEventTarget } from "@/sing/viewHelper";
import { isOnCommandOrCtrlKeyDown } from "@/store/utility";

export class EditNotesToolIdleState
implements State<SequencerStateDefinitions, Input, Context>
{
readonly id = "editNotesToolIdle";

onEnter() {}

process({
input,
context,
setNextState,
}: {
input: Input;
context: Context;
setNextState: SetNextState<SequencerStateDefinitions>;
}) {
const mouseButton = getButton(input.mouseEvent);
const selectedTrackId = context.selectedTrackId.value;

if (input.targetArea === "SequencerBody") {
context.guideLineTicks.value = getGuideLineTicks(
input.cursorPos,
context,
);
}

if (
input.mouseEvent.type === "mousedown" &&
mouseButton === "LEFT_BUTTON" &&
isSelfEventTarget(input.mouseEvent)
) {
if (input.targetArea === "SequencerBody") {
if (input.mouseEvent.shiftKey) {
setNextState("selectNotesWithRect", {
cursorPosAtStart: input.cursorPos,
returnStateId: this.id,
});
} else if (isOnCommandOrCtrlKeyDown(input.mouseEvent)) {
void context.store.actions.DESELECT_ALL_NOTES();
} else {
void context.store.actions.DESELECT_ALL_NOTES();
setNextState("addNote", {
cursorPosAtStart: input.cursorPos,
targetTrackId: selectedTrackId,
returnStateId: this.id,
});
}
} else if (input.targetArea === "Note") {
executeNotesSelectionProcess(context, input.mouseEvent, input.note);
setNextState("moveNote", {
cursorPosAtStart: input.cursorPos,
targetTrackId: selectedTrackId,
targetNoteIds: context.selectedNoteIds.value,
mouseDownNoteId: input.note.id,
returnStateId: this.id,
});
} else if (input.targetArea === "NoteLeftEdge") {
executeNotesSelectionProcess(context, input.mouseEvent, input.note);
setNextState("resizeNoteLeft", {
cursorPosAtStart: input.cursorPos,
targetTrackId: selectedTrackId,
targetNoteIds: context.selectedNoteIds.value,
mouseDownNoteId: input.note.id,
returnStateId: this.id,
});
} else if (input.targetArea === "NoteRightEdge") {
executeNotesSelectionProcess(context, input.mouseEvent, input.note);
setNextState("resizeNoteRight", {
cursorPosAtStart: input.cursorPos,
targetTrackId: selectedTrackId,
targetNoteIds: context.selectedNoteIds.value,
mouseDownNoteId: input.note.id,
returnStateId: this.id,
});
}
}
}

onExit() {}
}
6 changes: 5 additions & 1 deletion src/sing/sequencerStateMachine/states/erasePitchState.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SetNextState, State } from "@/sing/stateMachine";
import {
Context,
IdleStateId,
Input,
PositionOnSequencer,
SequencerStateDefinitions,
Expand All @@ -15,6 +16,7 @@ export class ErasePitchState

private readonly cursorPosAtStart: PositionOnSequencer;
private readonly targetTrackId: TrackId;
private readonly returnStateId: IdleStateId;

private currentCursorPos: PositionOnSequencer;

Expand All @@ -28,9 +30,11 @@ export class ErasePitchState
constructor(args: {
cursorPosAtStart: PositionOnSequencer;
targetTrackId: TrackId;
returnStateId: IdleStateId;
}) {
this.cursorPosAtStart = args.cursorPosAtStart;
this.targetTrackId = args.targetTrackId;
this.returnStateId = args.returnStateId;

this.currentCursorPos = args.cursorPosAtStart;
}
Expand Down Expand Up @@ -106,7 +110,7 @@ export class ErasePitchState
this.innerContext.executePreviewProcess = true;
} else if (input.mouseEvent.type === "mouseup") {
if (mouseButton === "LEFT_BUTTON") {
setNextState("idle", undefined);
setNextState(this.returnStateId, undefined);
}
}
}
Expand Down
Loading

0 comments on commit fce6ce8

Please sign in to comment.