Skip to content

Commit

Permalink
[project-s] ドラッグ周りの整理とプレビュー処理の追加 (#1680)
Browse files Browse the repository at this point in the history
* ドラッグ周りを整理

* 修正とリファクタリング

* 修正、カーソルやダブルクリック周りを変更

* 修正

* ダブルクリックの型変更

* === undefinedはなるべく避ける

* TODO: 例外処理は`UPDATE_NOTES`内に移す?

* コメント追加

* TODO: 例外処理は`REMOVE_SELECTED_NOTES`内に移す?

* Update src/components/Sing/ScoreSequencer.vue

* FIXME: 無効状態はstring以外の型にする

* FIXME: 関連する値を1つのobjectにまとめる

---------

Co-authored-by: Hiroshiba <[email protected]>
  • Loading branch information
sigprogramming and Hiroshiba authored Dec 28, 2023
1 parent f13a4ab commit 259e8a0
Show file tree
Hide file tree
Showing 8 changed files with 470 additions and 421 deletions.
658 changes: 392 additions & 266 deletions src/components/Sing/ScoreSequencer.vue

Large diffs are not rendered by default.

98 changes: 32 additions & 66 deletions src/components/Sing/SequencerNote.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div
:class="classNamesStr"
:class="classNames"
:style="{
transform: `translate3d(${positionX}px,${positionY}px,0)`,
}"
Expand All @@ -17,38 +17,37 @@
:width="barWidth"
xmlns="http://www.w3.org/2000/svg"
class="sequencer-note-bar"
focusable="true"
tabindex="0"
@dblclick.prevent.stop="removeNote"
@keydown.prevent="handleKeydown"
>
<g>
<rect
y="0"
x="0"
height="100%"
width="100%"
rx="2"
ry="2"
stroke-width="1"
class="sequencer-note-bar-body"
@mousedown.stop="handleMouseDown"
:class="{ 'cursor-move': !isPreview }"
@mousedown="onBodyMouseDown"
/>
<rect
y="-25%"
x="-4"
height="150%"
width="12"
fill-opacity="0"
class="sequencer-note-bar-draghandle"
@mousedown.stop="handleDragLeftStart"
:class="{ 'cursor-ew-resize': !isPreview }"
@mousedown="onLeftEdgeMouseDown"
/>
<rect
y="-25%"
:x="barWidth - 4"
:x="barWidth - 8"
width="12"
height="150%"
fill-opacity="0"
class="sequencer-note-bar-draghandle"
@mousedown.stop="handleDragRightStart"
:class="{ 'cursor-ew-resize': !isPreview }"
@mousedown="onRightEdgeMouseDown"
/>
</g>
</svg>
Expand All @@ -63,25 +62,16 @@ import {
getKeyBaseHeight,
tickToBaseX,
noteNumberToBaseY,
PREVIEW_SOUND_DURATION,
} from "@/helpers/singHelper";
export default defineComponent({
name: "SingSequencerNote",
props: {
note: { type: Object as PropType<Note>, required: true },
index: { type: Number, required: true },
cursorX: { type: Number },
cursorY: { type: Number },
isSelected: { type: Boolean },
isPreview: { type: Boolean },
},
emits: [
"handleNotesKeydown",
"handleDragMoveStart",
"handleDragRightStart",
"handleDragLeftStart",
],
emits: ["bodyMousedown", "rightEdgeMousedown", "leftEdgeMousedown"],
setup(props, { emit }) {
const store = useStore();
const state = store.state;
Expand All @@ -104,20 +94,16 @@ export default defineComponent({
const noteEndBaseX = tickToBaseX(noteEndTicks, tpqn.value);
return (noteEndBaseX - noteStartBaseX) * zoomX.value;
});
const classNamesStr = computed(() => {
if (state.selectedNoteIds.includes(props.note.id)) {
const classNames = computed(() => {
if (props.isSelected) {
return "sequencer-note selected";
}
if (state.overlappingNoteIds.includes(props.note.id)) {
if (state.overlappingNoteIds.has(props.note.id)) {
return "sequencer-note overlapping";
}
return "sequencer-note";
});
const removeNote = () => {
store.dispatch("REMOVE_NOTES", { noteIds: [props.note.id] });
};
const setLyric = (event: Event) => {
if (!(event.target instanceof HTMLInputElement)) {
return;
Expand All @@ -128,38 +114,16 @@ export default defineComponent({
}
};
const selectThisNote = () => {
store.dispatch("SELECT_NOTES", { noteIds: [props.note.id] });
store.dispatch("PLAY_PREVIEW_SOUND", {
noteNumber: props.note.noteNumber,
duration: PREVIEW_SOUND_DURATION,
});
};
const handleKeydown = (event: KeyboardEvent) => {
emit("handleNotesKeydown", event);
};
const handleMouseDown = (event: MouseEvent) => {
if (!state.selectedNoteIds.includes(props.note.id)) {
selectThisNote();
} else {
emit("handleDragMoveStart", event);
}
const onBodyMouseDown = (event: MouseEvent) => {
emit("bodyMousedown", event);
};
const handleDragRightStart = (event: MouseEvent) => {
if (!state.selectedNoteIds.includes(props.note.id)) {
selectThisNote();
}
emit("handleDragRightStart", event);
const onRightEdgeMouseDown = (event: MouseEvent) => {
emit("rightEdgeMousedown", event);
};
const handleDragLeftStart = (event: MouseEvent) => {
if (!state.selectedNoteIds.includes(props.note.id)) {
selectThisNote();
}
emit("handleDragLeftStart", event);
const onLeftEdgeMouseDown = (event: MouseEvent) => {
emit("leftEdgeMousedown", event);
};
return {
Expand All @@ -169,13 +133,11 @@ export default defineComponent({
positionY,
barHeight,
barWidth,
classNamesStr,
removeNote,
classNames,
setLyric,
handleKeydown,
handleDragRightStart,
handleDragLeftStart,
handleMouseDown,
onBodyMouseDown,
onRightEdgeMouseDown,
onLeftEdgeMouseDown,
};
},
});
Expand All @@ -195,7 +157,6 @@ export default defineComponent({
&.selected {
.sequencer-note-bar-body {
fill: darkorange; //
cursor: move;
}
}
Expand Down Expand Up @@ -227,6 +188,7 @@ export default defineComponent({
display: block;
position: relative;
}
.sequencer-note-bar-body {
fill: colors.$primary;
stroke: #fff;
Expand All @@ -236,7 +198,11 @@ export default defineComponent({
left: 0;
}
.sequencer-note-bar-draghandle {
.cursor-move {
cursor: move;
}
.cursor-ew-resize {
cursor: ew-resize;
}
</style>
2 changes: 2 additions & 0 deletions src/components/Sing/SequencerRuler.vue
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ export default defineComponent({
});
const onClick = (event: MouseEvent) => {
store.dispatch("DESELECT_ALL_NOTES");
const sequencerRulerElement = sequencerRuler.value;
if (!sequencerRulerElement) {
throw new Error("sequencerRulerElement is null.");
Expand Down
4 changes: 2 additions & 2 deletions src/components/Sing/ToolBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
icon="stop"
@click="stop"
></q-btn>
<q-btn flat round class="sing-transport-button" icon="loop"></q-btn>
<div class="sing-playhead-position">{{ playheadPositionStr }}</div>
<q-input
type="number"
Expand Down Expand Up @@ -382,7 +381,8 @@ export default defineComponent({
.sing-playhead-position {
font-size: 18px;
margin: 0 4px;
margin-left: 14px;
margin-right: 4px;
min-width: 82px;
}
Expand Down
14 changes: 7 additions & 7 deletions src/helpers/singHelper.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Note, Tempo, TimeSignature } from "@/store/type";

export const BEAT_TYPES = [2, 4, 8, 16];
export const MAX_SNAP_TYPE = 32;

export const DEFAULT_TPQN = 480;
export const DEFAULT_BPM = 120;
export const DEFAULT_BEATS = 4;
export const DEFAULT_BEAT_TYPE = 4;

const BASE_X_PER_QUARTER_NOTE = 120;
const BASE_Y_PER_NOTE_NUMBER = 30;
const BASE_Y_PER_SEMITONE = 30;

export const ZOOM_X_MIN = 0.2;
export const ZOOM_X_MAX = 1;
Expand Down Expand Up @@ -115,7 +116,7 @@ export function isTriplet(noteType: number) {
}

export function getKeyBaseHeight() {
return BASE_Y_PER_NOTE_NUMBER;
return BASE_Y_PER_SEMITONE;
}

export function tickToBaseX(ticks: number, tpqn: number) {
Expand All @@ -128,21 +129,20 @@ export function baseXToTick(baseX: number, tpqn: number) {

// NOTE: ノート番号が整数のときに、そのノート番号のキーの中央の位置を返します
export function noteNumberToBaseY(noteNumber: number) {
return (127.5 - noteNumber) * BASE_Y_PER_NOTE_NUMBER;
return (127.5 - noteNumber) * BASE_Y_PER_SEMITONE;
}

// NOTE: integerがfalseの場合は、ノート番号のキーの中央の位置が
// ちょうどそのノート番号となるように計算します
export function baseYToNoteNumber(baseY: number, integer = true) {
return integer
? 127 - Math.floor(baseY / BASE_Y_PER_NOTE_NUMBER)
: 127.5 - baseY / BASE_Y_PER_NOTE_NUMBER;
? 127 - Math.floor(baseY / BASE_Y_PER_SEMITONE)
: 127.5 - baseY / BASE_Y_PER_SEMITONE;
}

export function getSnapTypes(tpqn: number) {
const maxSnapType = 64;
return getRepresentableNoteTypes(tpqn).filter((value) => {
return value <= maxSnapType;
return value <= MAX_SNAP_TYPE;
});
}

Expand Down
Loading

0 comments on commit 259e8a0

Please sign in to comment.