This commit is contained in:
2024-06-01 18:52:46 +02:00
parent da27582b64
commit 80fa033a88
8 changed files with 135 additions and 104 deletions

View File

@@ -3,13 +3,12 @@ import { Bound } from "./utils";
export type UITool = export type UITool =
| "track-unit-type" | "track-unit-type"
| "eraser"
| "sticking"; | "sticking";
export class AppStateStore extends Bound { class AppStateStore extends Bound {
selectedTool = ref<UITool>("track-unit-type"); selectedTool = ref<UITool>("track-unit-type");
activeTrackUnitType = ref(0); activeTrackUnitType = ref<number | null>(0);
activeStickingType = ref(1); activeStickingType = ref<number | null>(1);
unitMouseStart = ref<string | null>(null); unitMouseStart = ref<string | null>(null);
selectingUnits = ref(false); selectingUnits = ref(false);
deselectingUnits = ref(false); deselectingUnits = ref(false);

View File

@@ -23,7 +23,7 @@ const TrackSerialSchema = z.object({
units: z.object({ units: z.object({
isOn: z.array(z.boolean()), isOn: z.array(z.boolean()),
type: z.array(z.number()), type: z.array(z.number()),
stickingType: z.array(z.number()), stickingType: z.array(z.number().nullable()),
}), }),
barCount: z.number(), barCount: z.number(),
loopLength: z.number(), loopLength: z.number(),
@@ -72,7 +72,7 @@ export function deserialise(serial: unknown, manager: BeatManager) {
export type TrackUnit = { export type TrackUnit = {
on: boolean, on: boolean,
type: number, type: number,
stickingType: number, stickingType: number | null,
}; };
export class Track extends EffectScoped { export class Track extends EffectScoped {
@@ -191,7 +191,7 @@ export class Track extends EffectScoped {
}; };
} }
setStickingType(index: number, stickingType: number): void { setStickingType(index: number, stickingType: number | null): void {
const unit = this.getUnitByIndex(index); const unit = this.getUnitByIndex(index);
if (!unit) { if (!unit) {
return; return;

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-delete"><path d="M21 4H8l-7 8 7 8h13a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2z"></path><line x1="18" y1="9" x2="12" y2="15"></line><line x1="12" y1="9" x2="18" y2="15"></line></svg>

After

Width:  |  Height:  |  Size: 374 B

View File

@@ -5,18 +5,21 @@
<div class="toolbox-button paint-button-cont" <div class="toolbox-button paint-button-cont"
:class="{ active: selectedTool === 'track-unit-type' }" :class="{ active: selectedTool === 'track-unit-type' }"
@click="selectedTool = 'track-unit-type'"> @click="selectedTool = 'track-unit-type'">
<div <track-unit-box
v-if="activeTrackUnitType !== null"
class="paint-button" class="paint-button"
:class="getClasses({ on: true, type: TrackUnitTypeList[activeTrackUnitType]!, stickingType: null })" /> :sticking-type="null" :on="true" :type="activeTrackUnitType" />
<icon v-else class="paint-button" icon-name="eraser" />
</div> </div>
<template #content> <template #content>
<div class="details"> <div class="details">
<div v-for="(type, i) in TrackUnitTypeList" <div v-for="(type, i) in [...TrackUnitTypeList, null]"
:key="type" :key="type ?? 'eraser'"
class="toolbox-button" class="toolbox-button track-unit-type"
:class="{ active: i === activeTrackUnitType }" :class="{ active: i === activeTrackUnitType || type === null && activeTrackUnitType === null }"
@click="activeTrackUnitType = i; selectedTool = 'track-unit-type'"> @click="activeTrackUnitType = type === null ? null : i; selectedTool = 'track-unit-type'">
<div :class="getClasses({ on: true, type, stickingType: null })" /> <track-unit-box v-if="type !== null" :sticking-type="null" :on="true" :type="i" />
<icon v-else icon-name="eraser" />
</div> </div>
</div> </div>
</template> </template>
@@ -24,7 +27,7 @@
<dropdown> <dropdown>
<icon <icon
class="toolbox-button" class="toolbox-button"
:icon-name="PaintableTrackUnitStickingTypeList[activeStickingType]!" :icon-name="activeStickingType ? (PaintableTrackUnitStickingTypeList[activeStickingType] ?? 'eraser') : 'eraser'"
:class="{ active: selectedTool === 'sticking' }" :class="{ active: selectedTool === 'sticking' }"
@click="selectedTool = 'sticking'" /> @click="selectedTool = 'sticking'" />
<template #content> <template #content>
@@ -36,16 +39,15 @@
@click="activeStickingType = i; selectedTool = 'sticking'"> @click="activeStickingType = i; selectedTool = 'sticking'">
<icon :icon-name="StickingTypeIconMap[stickingType]" /> <icon :icon-name="StickingTypeIconMap[stickingType]" />
</div> </div>
<div
class="toolbox-button"
:class="{ active: activeStickingType === null }"
@click="activeStickingType = null; selectedTool = 'sticking'">
<icon icon-name="eraser" />
</div>
</div> </div>
</template> </template>
</dropdown> </dropdown>
<dropdown>
<icon
class="toolbox-button"
icon-name="eraser"
:class="{ active: selectedTool === 'eraser' }"
@click="selectedTool = 'eraser'" />
</dropdown>
</div> </div>
</div> </div>
</template> </template>
@@ -56,7 +58,7 @@
import { StickingTypeIconMap } from "@/ui/TrackUnit/trackUnit"; import { StickingTypeIconMap } from "@/ui/TrackUnit/trackUnit";
import Icon from "@/ui/Widgets/Icon/Icon.vue"; import Icon from "@/ui/Widgets/Icon/Icon.vue";
import Dropdown from '@/ui/Widgets/Dropdown/Dropdown.vue'; import Dropdown from '@/ui/Widgets/Dropdown/Dropdown.vue';
import { getClasses } from "@/ui/TrackUnit/trackUnit"; import TrackUnitBox from "@/ui/TrackUnitBox/TrackUnitBox.vue";
const { const {
selectedTool, selectedTool,
@@ -86,12 +88,19 @@
padding: 0; padding: 0;
} }
.track-unit-type {
margin: 5em;
}
.toolbox-button { .toolbox-button {
cursor: pointer; cursor: pointer;
color: black; color: black;
&.eraser {
background-color: black;
}
&.paint-button-cont { &.paint-button-cont {
padding: 0.25em;
background-color: var(--color-ui-bg-dark); background-color: var(--color-ui-bg-dark);
&:hover { &:hover {
@@ -111,10 +120,6 @@
} }
.paint-button { .paint-button {
height: 1.5em;
width: 1.5em;
background-color: black;
&.active { &.active {
background-color: var(--color-ui-neutral-dark); background-color: var(--color-ui-neutral-dark);
} }

View File

@@ -54,7 +54,9 @@
function toggle(index: number) { function toggle(index: number) {
if (!track.value) return; if (!track.value) return;
track.value.toggleUnit(index); if (selectedTool.value === 'track-unit-type') {
track.value.toggleUnit(index);
}
if (track.value.getUnitByIndex(index)?.on) { if (track.value.getUnitByIndex(index)?.on) {
applyCurrentToolToTrackUnit(index); applyCurrentToolToTrackUnit(index);
} }
@@ -75,10 +77,7 @@
track.value?.setStickingType(index, activeStickingType.value); track.value?.setStickingType(index, activeStickingType.value);
break; break;
case "track-unit-type": case "track-unit-type":
track.value?.updateUnit(index, { on: true, type: activeTrackUnitType.value }); track.value?.updateUnit(index, { on: activeTrackUnitType.value === null ? false : true, type: activeTrackUnitType.value === null ? undefined : activeTrackUnitType.value });
break;
case "eraser":
track.value?.setUnitOn(index, false);
break; break;
} }
} }

View File

@@ -1,5 +1,9 @@
<template> <template>
<div :class="classes" <track-unit-box
class="track-unit"
:sticking-type="stickingType"
:type="type"
:on="on"
@mousedown="handleMouseDown" @mousedown="handleMouseDown"
@mouseup="handleMouseUp" @mouseup="handleMouseUp"
@mouseover="handleMouseOver" @mouseover="handleMouseOver"
@@ -7,21 +11,16 @@
@mouseout="handleMouseOut" @mouseout="handleMouseOut"
@touchstart="handleTouchStart" @touchstart="handleTouchStart"
@touchend="handleTouchEnd" @touchend="handleTouchEnd"
@contextmenu.prevent.stop="() => false"> @contextmenu.prevent.stop="() => false"/>
<icon v-if="iconName" :icon-name="iconName" />
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { TrackUnitStickingTypeList, TrackUnitTypeList } from "@/Track";
import Icon from "@/ui/Widgets/Icon/Icon.vue";
import { StickingTypeIconMap, getClasses } from "./trackUnit";
import { computed } from "vue";
import { useAppStateStore } from "@/AppState"; import { useAppStateStore } from "@/AppState";
import TrackUnitBox from "@/ui/TrackUnitBox/TrackUnitBox.vue";
const props = defineProps<{ const props = defineProps<{
id: string, id: string,
stickingType: number, stickingType: number | null,
type: number, type: number,
on: boolean, on: boolean,
}>(); }>();
@@ -44,22 +43,6 @@
let mouseHeld = false; let mouseHeld = false;
let movement = 0; let movement = 0;
const classes = computed(() => getClasses({
on: props.on,
stickingType: TrackUnitStickingTypeList[props.stickingType] ?? null,
type: TrackUnitTypeList[props.type] ?? 'Normal',
highlightable: true,
}));
const iconName = computed(() => {
const type = TrackUnitStickingTypeList[props.stickingType];
if (type) {
StickingTypeIconMap[type];
} else {
return null;
}
});
function handleMouseDown(ev: MouseEvent): void { function handleMouseDown(ev: MouseEvent): void {
blockNextMouseUp = false; blockNextMouseUp = false;
if (ev.button === 0) { if (ev.button === 0) {
@@ -125,53 +108,8 @@
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.track-unit {
width: 2em;
height: 2em;
margin-right: 4px;
background-color: #464646;
border-color: #464646;
border-width: 0.1em 0.1em 0.1em 0.1em;
border-style: solid;
display: inline-block;
transition: background-color 100ms, border-color 100ms;
cursor: pointer;
}
.track-unit.highlightable:hover {
border-color: #5f5f5f;
background-color: #5f5f5f;
transition: none;
}
.vertical-mode .track-unit { .vertical-mode .track-unit {
margin-bottom: 4px; margin-bottom: 4px;
display: block; display: block;
} }
.track-unit.on {
border-color: var(--color-ui-accent);
background-color: var(--color-ui-accent);
transition: none;
}
.track-unit.on.Accent, .track-unit.on.Accent.highlightable:hover {
border-color: var(--color-ui-neutral-light);
}
.track-unit.on.highlightable:hover {
border-color: var(--color-ui-accent-hover);
background-color: var(--color-ui-accent-hover);
}
.track-unit.on.Ghost {
opacity: 60%;
}
.track-unit .icon-view {
display: none;
}
.track-unit.on.icon-visible .icon-view {
display: block;
}
</style> </style>

View File

@@ -0,0 +1,87 @@
<template>
<div class="track-unit-box" :class="classes">
<icon v-if="iconName" :icon-name="iconName" />
</div>
</template>
<script setup lang="ts">
import { TrackUnitStickingTypeList, TrackUnitTypeList } from "@/Track";
import Icon from "@/ui/Widgets/Icon/Icon.vue";
import { StickingTypeIconMap, getClasses } from "@/ui/TrackUnit/trackUnit";
import { computed } from "vue";
const props = defineProps<{
stickingType: number | null,
type: number,
on: boolean,
}>();
const classes = computed(() => getClasses({
on: props.on,
stickingType: props.stickingType ? (TrackUnitStickingTypeList[props.stickingType] ?? null) : null,
type: TrackUnitTypeList[props.type] ?? 'Normal',
highlightable: true,
}));
const iconName = computed(() => {
if (props.stickingType) {
const type = TrackUnitStickingTypeList[props.stickingType] ?? null;
if (type) {
return StickingTypeIconMap[type];
}
}
return null;
});
</script>
<style scoped lang="scss">
.track-unit-box {
width: 2em;
height: 2em;
margin-right: 4px;
background-color: #464646;
border-color: #464646;
border-width: 0.1em 0.1em 0.1em 0.1em;
border-style: solid;
display: inline-block;
transition: background-color 100ms, border-color 100ms;
cursor: pointer;
&.highlightable {
&:hover {
border-color: #5f5f5f;
background-color: #5f5f5f;
transition: none;
}
&.on {
border-color: var(--color-ui-accent-hover);
background-color: var(--color-ui-accent-hover);
}
}
.icon-view {
display: none;
}
&.on {
border-color: var(--color-ui-accent);
background-color: var(--color-ui-accent);
transition: none;
&.Accent, &.Accent.highlightable:hover {
border-color: var(--color-ui-neutral-light);
}
&.Ghost {
opacity: 60%;
}
&.icon-visible .icon-view {
display: block;
}
}
}
</style>

View File

@@ -10,6 +10,7 @@ import RightFoot from "@/assets/svgs/RF.png";
import Eraser from "@/assets/svgs/eraser-fill.svg"; 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";
export const IconUrlMap = { export const IconUrlMap = {
arrowClockwise: ArrowClockwise, arrowClockwise: ArrowClockwise,
@@ -24,6 +25,7 @@ export const IconUrlMap = {
eraser: Eraser, eraser: Eraser,
upload: Upload, upload: Upload,
save: Floppy, save: Floppy,
delete: Delete,
} as const; } as const;
export type IconName = keyof typeof IconUrlMap; export type IconName = keyof typeof IconUrlMap;