79 lines
1.8 KiB
TypeScript
79 lines
1.8 KiB
TypeScript
|
|
import { BaseTool } from './base-tool';
|
||
|
|
import type { PointerState } from '@/types';
|
||
|
|
import { useSelectionStore } from '@/store/selection-store';
|
||
|
|
import { useLayerStore } from '@/store/layer-store';
|
||
|
|
import {
|
||
|
|
createMagicWandMask,
|
||
|
|
createSelection,
|
||
|
|
combineMasks,
|
||
|
|
} from '@/lib/selection-utils';
|
||
|
|
|
||
|
|
export class MagicWandTool extends BaseTool {
|
||
|
|
constructor() {
|
||
|
|
super('Magic Wand');
|
||
|
|
}
|
||
|
|
|
||
|
|
onPointerDown(pointer: PointerState): void {
|
||
|
|
this.isActive = true;
|
||
|
|
|
||
|
|
const layer = this.getActiveLayer();
|
||
|
|
if (!layer?.canvas) return;
|
||
|
|
|
||
|
|
const ctx = layer.canvas.getContext('2d');
|
||
|
|
if (!ctx) return;
|
||
|
|
|
||
|
|
const x = Math.floor(pointer.x);
|
||
|
|
const y = Math.floor(pointer.y);
|
||
|
|
|
||
|
|
if (
|
||
|
|
x < 0 ||
|
||
|
|
x >= layer.canvas.width ||
|
||
|
|
y < 0 ||
|
||
|
|
y >= layer.canvas.height
|
||
|
|
) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const imageData = ctx.getImageData(
|
||
|
|
0,
|
||
|
|
0,
|
||
|
|
layer.canvas.width,
|
||
|
|
layer.canvas.height
|
||
|
|
);
|
||
|
|
|
||
|
|
const { selectionMode, feather, tolerance, activeSelection } =
|
||
|
|
useSelectionStore.getState();
|
||
|
|
|
||
|
|
const newMask = createMagicWandMask(x, y, imageData, tolerance);
|
||
|
|
|
||
|
|
let finalMask = newMask;
|
||
|
|
|
||
|
|
// Combine with existing selection if needed
|
||
|
|
if (activeSelection && selectionMode !== 'new') {
|
||
|
|
finalMask = combineMasks(activeSelection.mask, newMask, selectionMode);
|
||
|
|
}
|
||
|
|
|
||
|
|
const selection = createSelection(layer.id, finalMask, feather);
|
||
|
|
useSelectionStore.getState().setActiveSelection(selection);
|
||
|
|
|
||
|
|
this.isActive = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
onPointerMove(): void {
|
||
|
|
// Magic wand doesn't need pointer move
|
||
|
|
}
|
||
|
|
|
||
|
|
onPointerUp(): void {
|
||
|
|
this.isActive = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
getCursor(): string {
|
||
|
|
return 'crosshair';
|
||
|
|
}
|
||
|
|
|
||
|
|
private getActiveLayer() {
|
||
|
|
const { activeLayerId, layers } = useLayerStore.getState();
|
||
|
|
return layers.find((l) => l.id === activeLayerId);
|
||
|
|
}
|
||
|
|
}
|