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