update
This commit is contained in:
@@ -8,6 +8,7 @@ export interface BeatManager {
|
||||
}
|
||||
|
||||
type BeatGroupInitOptions = {
|
||||
displaySticking?: boolean,
|
||||
barCount: number;
|
||||
isLooping: boolean;
|
||||
timeSigUp: number;
|
||||
@@ -24,6 +25,7 @@ const BeatSerialSchema = z.object({
|
||||
globalLoopLength: z.number(),
|
||||
globalIsLooping: z.boolean(),
|
||||
useAutoBeatLength: z.boolean(),
|
||||
displaySticking: z.boolean(),
|
||||
barSettingsLocked: z.boolean(),
|
||||
name: z.string(),
|
||||
});
|
||||
@@ -44,7 +46,7 @@ export class Beat extends EffectScoped {
|
||||
barSettingsLocked: Ref<boolean>;
|
||||
name: Ref<string>;
|
||||
saveDirty = ref(false);
|
||||
displaySticking = ref(false);
|
||||
displaySticking: Ref<boolean>;
|
||||
|
||||
constructor(opts: BeatGroupInitOptions) {
|
||||
super();
|
||||
@@ -91,6 +93,7 @@ export class Beat extends EffectScoped {
|
||||
this.useAutoBeatLength = ref(opts.useAutoBeatLength ?? false);
|
||||
this.barSettingsLocked = computed(() => this.useAutoBeatLength.value);
|
||||
this.name = ref(opts.name ?? `Beat-${ this.id }`);
|
||||
this.displaySticking = ref(opts.displaySticking ?? false);
|
||||
|
||||
watch([this.barCount, this.timeSigUp, this.name], ([newBarCount, newTimeSigUp]) => {
|
||||
for (const track of this.tracks.value) {
|
||||
@@ -169,6 +172,7 @@ export class Beat extends EffectScoped {
|
||||
|
||||
serialise(): Readonly<BeatSerial> {
|
||||
return {
|
||||
displaySticking: this.displaySticking.value,
|
||||
tracks: this.tracks.value.map(track => track.serialise()),
|
||||
barCount: this.barCount.value,
|
||||
timeSigUp: this.timeSigUp.value,
|
||||
@@ -189,6 +193,7 @@ export function deserialise(serial: unknown): Beat | null {
|
||||
}
|
||||
const beat = parse.data;
|
||||
const newBeat = Beat.asScoped({
|
||||
displaySticking: beat.displaySticking,
|
||||
loopLength: beat.globalLoopLength,
|
||||
barCount: beat.barCount,
|
||||
isLooping: beat.globalIsLooping,
|
||||
|
||||
26
src/Track.ts
26
src/Track.ts
@@ -4,6 +4,7 @@ import type { BeatManager } from "./Beat";
|
||||
import { z } from "zod";
|
||||
|
||||
export type TrackInitOptions = {
|
||||
visible?: boolean,
|
||||
manager: BeatManager,
|
||||
timeSig?: {
|
||||
up: number,
|
||||
@@ -28,6 +29,7 @@ const TrackSerialSchema = z.object({
|
||||
barCount: z.number(),
|
||||
loopLength: z.number(),
|
||||
looping: z.boolean(),
|
||||
visible: z.boolean(),
|
||||
});
|
||||
export type TrackSerial = z.infer<typeof TrackSerialSchema>;
|
||||
|
||||
@@ -46,21 +48,22 @@ export function deserialise(serial: unknown, manager: BeatManager) {
|
||||
if (!parse.success) {
|
||||
throw new Error("Invalid track serial.");
|
||||
}
|
||||
const beat = parse.data;
|
||||
const units = beat.units.isOn.map((isOn, i) => ({
|
||||
const track = parse.data;
|
||||
const units = track.units.isOn.map((isOn, i) => ({
|
||||
on: isOn,
|
||||
type: beat.units.type[i] ?? 0,
|
||||
stickingType: beat.units.stickingType[i] ?? null,
|
||||
type: track.units.type[i] ?? 0,
|
||||
stickingType: track.units.stickingType[i] ?? null,
|
||||
}));
|
||||
return Track.asScoped({
|
||||
visible: track.visible,
|
||||
manager,
|
||||
barCount: beat.barCount,
|
||||
isLooping: beat.looping,
|
||||
loopLength: beat.loopLength,
|
||||
name: beat.name,
|
||||
barCount: track.barCount,
|
||||
isLooping: track.looping,
|
||||
loopLength: track.loopLength,
|
||||
name: track.name,
|
||||
timeSig: {
|
||||
up: beat.timeSigUp,
|
||||
down: beat.timeSigDown,
|
||||
up: track.timeSigUp,
|
||||
down: track.timeSigDown,
|
||||
},
|
||||
units,
|
||||
});
|
||||
@@ -83,6 +86,7 @@ export class Track extends EffectScoped {
|
||||
barCount: Ref<number>;
|
||||
loopLength: Ref<number>;
|
||||
looping: Ref<boolean>;
|
||||
visible: Ref<boolean>;
|
||||
|
||||
constructor(options: TrackInitOptions) {
|
||||
super();
|
||||
@@ -125,6 +129,7 @@ export class Track extends EffectScoped {
|
||||
},
|
||||
});
|
||||
this.looping = ref(options?.isLooping ?? false);
|
||||
this.visible = ref(options?.visible ?? true);
|
||||
|
||||
watch(this.unitRecord, () => this.manager.notifyChange());
|
||||
watch([this.barCount, this.timeSigDown, this.timeSigUp], () => this.updateTrackUnitLength(), { immediate: true });
|
||||
@@ -170,6 +175,7 @@ export class Track extends EffectScoped {
|
||||
|
||||
serialise(): Readonly<TrackSerial> {
|
||||
return {
|
||||
visible: this.visible.value,
|
||||
name: this.name.value,
|
||||
timeSigUp: this.timeSigUp.value,
|
||||
timeSigDown: this.timeSigDown.value,
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
@change="onMove"
|
||||
item-key="index">
|
||||
<template #item="{ element }">
|
||||
<div class="beat-line">
|
||||
<div v-if="element.track.visible.value" class="beat-line">
|
||||
<editable-text-field class="track-name" v-model="element.track.name.value" />
|
||||
<span class="handle"><icon color="var(--color-ui-neutral-dark)" icon-name="list" /></span>
|
||||
<track-view :beat-index="beatIndex"
|
||||
@@ -44,7 +44,7 @@
|
||||
import Draggable from "vuedraggable";
|
||||
import { TrackUnitStickingTypeList, type Track } from "@/Track";
|
||||
import Icon from "@/ui/Widgets/Icon/Icon.vue";
|
||||
import { StickingTypeIconMap } from "../TrackUnit/trackUnit";
|
||||
import { StickingTypeIconMap } from "../TrackUnit/trackUnit";
|
||||
|
||||
const props = defineProps<{
|
||||
beatIndex: number,
|
||||
|
||||
@@ -11,13 +11,17 @@
|
||||
</div>
|
||||
<div class="loop-settings-option" :class="{ hide: !track.looping.value }">
|
||||
<number-input v-model="track.loopLength.value" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="visibility">
|
||||
<icon color="var(--color-ui-neutral-dark)" :icon-name="track.visible.value ? 'eye' : 'eyeOff'" @click="track.visible.value = !track.visible.value"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import NumberInput from "@/ui/Widgets/NumberInput/NumberInput.vue";
|
||||
import Icon from "@/ui/Widgets/Icon/Icon.vue";
|
||||
import BoolBox from "@/ui/Widgets/BoolBox/BoolBox.vue";
|
||||
import ActionButton from "@/ui/Widgets/ActionButton/ActionButton.vue";
|
||||
import EditableTextField from "@/ui/Widgets/EditableTextField/EditableTextField.vue";
|
||||
@@ -39,7 +43,7 @@
|
||||
min-width: 100%;
|
||||
height: 2em;
|
||||
}
|
||||
p
|
||||
|
||||
.track-settings-title-container > div {
|
||||
width: 100%;
|
||||
font-weight: bold;
|
||||
@@ -81,4 +85,8 @@ p
|
||||
flex: auto;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.visibility {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -11,6 +11,8 @@ import Eraser from "@/assets/svgs/eraser-fill.svg";
|
||||
import Upload from "@/assets/svgs/upload.svg";
|
||||
import Floppy from "@/assets/svgs/floppy2-fill.svg";
|
||||
import Delete from "@/assets/svgs/delete.svg";
|
||||
import Eye from "@/assets/svgs/eye.svg";
|
||||
import EyeOff from "@/assets/svgs/eye-off.svg";
|
||||
|
||||
export const IconUrlMap = {
|
||||
arrowClockwise: ArrowClockwise,
|
||||
@@ -26,6 +28,8 @@ export const IconUrlMap = {
|
||||
upload: Upload,
|
||||
save: Floppy,
|
||||
delete: Delete,
|
||||
eye: Eye,
|
||||
eyeOff: EyeOff,
|
||||
} as const;
|
||||
|
||||
export type IconName = keyof typeof IconUrlMap;
|
||||
|
||||
Reference in New Issue
Block a user