[FEAT] Replace img
This commit is contained in:
@@ -40,10 +40,10 @@
|
||||
@touchmove="handleTouchMove"
|
||||
@touchend="stopDrag"
|
||||
@contextmenu.prevent.stop
|
||||
@dragover="handleDragOver"
|
||||
@dragenter="handleDragEnter"
|
||||
@dragleave="onDragLeave"
|
||||
@drop="handleDrop"
|
||||
@dragover="handleGridDragOver"
|
||||
@dragenter="handleGridDragEnter"
|
||||
@dragleave="handleGridDragLeave"
|
||||
@drop="handleGridDrop"
|
||||
:class="{ 'ring-4 ring-blue-500 ring-opacity-50': isDragOver }"
|
||||
>
|
||||
<!-- Grid cells -->
|
||||
@@ -174,7 +174,7 @@
|
||||
import { ref, onMounted, watch, onUnmounted, toRef, computed, nextTick } from 'vue';
|
||||
import { useSettingsStore } from '@/stores/useSettingsStore';
|
||||
import type { Sprite } from '@/types/sprites';
|
||||
import { useDragSprite } from '@/composables/useDragSprite';
|
||||
import { useDragSprite, type CellPosition } from '@/composables/useDragSprite';
|
||||
import { useFileDrop } from '@/composables/useFileDrop';
|
||||
import { useGridMetrics } from '@/composables/useGridMetrics';
|
||||
import { useBackgroundStyles } from '@/composables/useBackgroundStyles';
|
||||
@@ -204,6 +204,7 @@
|
||||
(e: 'removeSprites', ids: string[]): void;
|
||||
(e: 'replaceSprite', id: string, file: File): void;
|
||||
(e: 'addSprite', file: File, index?: number): void;
|
||||
(e: 'addSprites', files: File[], index?: number): void;
|
||||
(e: 'addSpriteWithResize', file: File): void;
|
||||
(e: 'rotateSprite', id: string, angle: number): void;
|
||||
(e: 'flipSprite', id: string, direction: 'horizontal' | 'vertical'): void;
|
||||
@@ -541,10 +542,50 @@
|
||||
}
|
||||
};
|
||||
|
||||
const onDragLeave = (event: DragEvent) => {
|
||||
// Grid Drag & Drop
|
||||
// Grid Drag & Drop
|
||||
|
||||
const handleGridDragEnter = (event: DragEvent) => {
|
||||
handleDragEnter(event);
|
||||
};
|
||||
|
||||
const handleGridDragOver = (event: DragEvent) => {
|
||||
handleDragOver(event);
|
||||
};
|
||||
|
||||
const handleGridDragLeave = (event: DragEvent) => {
|
||||
handleDragLeave(event, gridContainerRef.value);
|
||||
};
|
||||
|
||||
const handleGridDrop = (event: DragEvent) => {
|
||||
handleDragLeave(event, gridContainerRef.value); // Reset drag over state
|
||||
isDragOver.value = false;
|
||||
|
||||
if (!event.dataTransfer?.files.length) return;
|
||||
|
||||
// Calculate target cell immediately on drop
|
||||
let targetCellIndex: number | undefined;
|
||||
const pos = getMousePosition(event as unknown as MouseEvent, props.zoom);
|
||||
if (pos) {
|
||||
const cell = findCellAtPosition(pos.x, pos.y);
|
||||
if (cell) {
|
||||
targetCellIndex = cell.index;
|
||||
}
|
||||
}
|
||||
|
||||
const files = Array.from(event.dataTransfer.files).filter(file => file.type.startsWith('image/'));
|
||||
|
||||
if (files.length === 0) return;
|
||||
|
||||
if (targetCellIndex !== undefined) {
|
||||
// Add sprites starting from the target cell index
|
||||
emit('addSprites', files, targetCellIndex);
|
||||
} else {
|
||||
// Fallback to default behavior (append)
|
||||
emit('addSprites', files);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('mouseup', stopDrag);
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
|
||||
@@ -286,6 +286,63 @@ export const useLayers = () => {
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
|
||||
const addSprites = async (files: File[], index?: number) => {
|
||||
const l = activeLayer.value;
|
||||
if (!l) return;
|
||||
|
||||
const promises = files.map(file => {
|
||||
return new Promise<Sprite>((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = e => {
|
||||
const url = e.target?.result as string;
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
resolve({
|
||||
id: crypto.randomUUID(),
|
||||
file,
|
||||
img,
|
||||
url,
|
||||
width: img.width,
|
||||
height: img.height,
|
||||
x: 0,
|
||||
y: 0,
|
||||
rotation: 0,
|
||||
flipX: false,
|
||||
flipY: false,
|
||||
});
|
||||
};
|
||||
img.onerror = () => {
|
||||
console.error('Failed to load sprite image:', file.name);
|
||||
reject(new Error(`Failed to load sprite image: ${file.name}`));
|
||||
};
|
||||
img.src = url;
|
||||
};
|
||||
reader.onerror = () => {
|
||||
console.error('Failed to read sprite image file:', file.name);
|
||||
reject(new Error(`Failed to read sprite image file: ${file.name}`));
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
const newSprites = await Promise.all(promises);
|
||||
const currentSprites = [...l.sprites];
|
||||
|
||||
if (typeof index === 'number') {
|
||||
while (currentSprites.length < index) {
|
||||
currentSprites.push(createEmptySprite());
|
||||
}
|
||||
currentSprites.splice(index, 0, ...newSprites);
|
||||
} else {
|
||||
currentSprites.push(...newSprites);
|
||||
}
|
||||
l.sprites = currentSprites;
|
||||
} catch (error) {
|
||||
console.error('Error adding sprites:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const processImageFiles = async (files: File[]) => {
|
||||
for (const f of files) addSprite(f);
|
||||
};
|
||||
@@ -376,6 +433,7 @@ export const useLayers = () => {
|
||||
flipSprite,
|
||||
replaceSprite,
|
||||
addSprite,
|
||||
addSprites,
|
||||
processImageFiles,
|
||||
alignSprites,
|
||||
addLayer,
|
||||
|
||||
@@ -309,6 +309,7 @@
|
||||
@flip-sprite="flipSprite"
|
||||
@copy-sprite-to-frame="copySpriteToFrame"
|
||||
@open-pixel-editor="openPixelEditor"
|
||||
@add-sprites="addSprites"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="activeTab === 'preview'" class="h-full flex items-center justify-center">
|
||||
@@ -372,8 +373,29 @@
|
||||
const projectStore = useProjectStore();
|
||||
const { closeProject, loadProjectData } = useProjectManager();
|
||||
const settingsStore = useSettingsStore();
|
||||
const { layers, visibleLayers, activeLayer, activeLayerId, columns, updateSpritePosition, updateSpriteInLayer, updateSpriteCell, removeSprite, removeSprites, replaceSprite, addSprite, processImageFiles, alignSprites, addLayer, removeLayer, moveLayer, rotateSprite, flipSprite, copySpriteToFrame } =
|
||||
useLayers();
|
||||
const {
|
||||
layers,
|
||||
visibleLayers,
|
||||
activeLayer,
|
||||
activeLayerId,
|
||||
columns,
|
||||
updateSpritePosition,
|
||||
updateSpriteInLayer,
|
||||
updateSpriteCell,
|
||||
removeSprite,
|
||||
removeSprites,
|
||||
replaceSprite,
|
||||
addSprite,
|
||||
addSprites,
|
||||
processImageFiles,
|
||||
alignSprites,
|
||||
addLayer,
|
||||
removeLayer,
|
||||
moveLayer,
|
||||
rotateSprite,
|
||||
flipSprite,
|
||||
copySpriteToFrame,
|
||||
} = useLayers();
|
||||
|
||||
const { downloadSpritesheet, exportSpritesheetJSON, importSpritesheetJSON, downloadAsGif, downloadAsZip } = useExportLayers(
|
||||
layers,
|
||||
|
||||
Reference in New Issue
Block a user