This commit is contained in:
2025-11-22 02:52:36 +01:00
parent 5cc4eb8731
commit 097df1f5de
8 changed files with 726 additions and 198 deletions

View File

@@ -100,7 +100,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, watch, onUnmounted, toRef } from 'vue';
import { ref, onMounted, watch, onUnmounted, toRef, computed } from 'vue';
import { useSettingsStore } from '@/stores/useSettingsStore';
import type { Sprite } from '@/types/sprites';
import { useCanvas2D } from '@/composables/useCanvas2D';
@@ -108,8 +108,11 @@
import { useDragSprite } from '@/composables/useDragSprite';
import { useFileDrop } from '@/composables/useFileDrop';
import type { Layer } from '@/types/sprites';
const props = defineProps<{
sprites: Sprite[];
layers: Layer[];
activeLayerId: string;
columns: number;
}>();
@@ -158,7 +161,7 @@
findSpriteAtPosition,
calculateMaxDimensions,
} = useDragSprite({
sprites: toRef(props, 'sprites'),
sprites: computed(() => (props.layers.find(l => l.id === props.activeLayerId)?.sprites ?? [])),
columns: toRef(props, 'columns'),
zoom,
allowCellSwap,
@@ -169,8 +172,10 @@
onDraw: drawCanvas,
});
const activeSprites = computed(() => props.layers.find(l => l.id === props.activeLayerId)?.sprites ?? []);
const { isDragOver, handleDragOver, handleDragEnter, handleDragLeave, handleDrop } = useFileDrop({
sprites: props.sprites,
sprites: activeSprites,
onAddSprite: file => emit('addSprite', file),
onAddSpriteWithResize: file => emit('addSpriteWithResize', file),
});
@@ -280,7 +285,8 @@
const { maxWidth, maxHeight, negativeSpacing } = calculateMaxDimensions();
// Set canvas size
const rows = Math.max(1, Math.ceil(props.sprites.length / props.columns));
const maxLen = Math.max(1, ...props.layers.map(l => (l.visible ? l.sprites.length : 1)));
const rows = Math.max(1, Math.ceil(maxLen / props.columns));
canvas2D.setCanvasSize(maxWidth * props.columns, maxHeight * rows);
// Clear canvas
@@ -307,42 +313,42 @@
// If showing all sprites, draw all sprites with transparency in each cell
if (showAllSprites.value) {
for (let cellIndex = 0; cellIndex < props.sprites.length; cellIndex++) {
const total = Math.max(...props.layers.map(l => (l.visible ? l.sprites.length : 0)));
for (let cellIndex = 0; cellIndex < total; cellIndex++) {
const cellCol = cellIndex % props.columns;
const cellRow = Math.floor(cellIndex / props.columns);
const cellX = Math.floor(cellCol * maxWidth);
const cellY = Math.floor(cellRow * maxHeight);
// Draw all sprites with transparency in this cell
// Position at bottom-right with negative spacing offset
props.sprites.forEach((sprite, spriteIndex) => {
if (spriteIndex !== cellIndex) {
canvas2D.drawImage(sprite.img, cellX + negativeSpacing + sprite.x, cellY + negativeSpacing + sprite.y, 0.3);
}
props.layers.forEach(layer => {
if (!layer.visible) return;
const sprite = layer.sprites[cellIndex];
if (sprite) canvas2D.drawImage(sprite.img, cellX + negativeSpacing + sprite.x, cellY + negativeSpacing + sprite.y, 0.35);
});
}
}
// Draw sprites normally
props.sprites.forEach((sprite, index) => {
// Skip the active sprite if we're showing a ghost instead
if (activeSpriteId.value === sprite.id && ghostSprite.value) {
return;
}
// Draw layers in order; active layer will be interactable
props.layers.forEach(layer => {
if (!layer.visible) return;
layer.sprites.forEach((sprite, index) => {
// Skip the active sprite if we're showing a ghost instead
if (activeSpriteId.value === sprite.id && ghostSprite.value) return;
const col = index % props.columns;
const row = Math.floor(index / props.columns);
const col = index % props.columns;
const row = Math.floor(index / props.columns);
const cellX = Math.floor(col * maxWidth);
const cellY = Math.floor(row * maxHeight);
const cellX = Math.floor(col * maxWidth);
const cellY = Math.floor(row * maxHeight);
// Draw sprite with negative spacing offset (bottom-right positioning)
canvas2D.drawImage(sprite.img, cellX + negativeSpacing + sprite.x, cellY + negativeSpacing + sprite.y);
const alpha = layer.id === props.activeLayerId ? 1 : 0.85;
canvas2D.drawImage(sprite.img, cellX + negativeSpacing + sprite.x, cellY + negativeSpacing + sprite.y, alpha);
});
});
// Draw ghost sprite if we're dragging between cells
if (ghostSprite.value && activeSpriteId.value) {
const sprite = props.sprites.find(s => s.id === activeSpriteId.value);
const sprite = activeSprites.value.find(s => s.id === activeSpriteId.value);
if (sprite) {
canvas2D.drawImage(sprite.img, ghostSprite.value.x, ghostSprite.value.y, 0.6);
}
@@ -362,7 +368,8 @@
const imagesWithListeners = new WeakSet<HTMLImageElement>();
const attachImageListeners = () => {
canvas2D.attachImageListeners(props.sprites, handleForceRedraw, imagesWithListeners);
const sprites = props.layers.flatMap(l => l.sprites);
canvas2D.attachImageListeners(sprites, handleForceRedraw, imagesWithListeners);
};
onMounted(() => {