| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import { state } from '../state.js';
|
| import { canvasCoords } from '../canvas-coords.js';
|
|
|
| const STROKE_TOOLS = new Set(['brush', 'eraser', 'inpaint']);
|
|
|
| function strokeLabel(tool) {
|
| if (tool === 'brush') return 'Brush stroke';
|
| if (tool === 'eraser') return 'Eraser stroke';
|
| if (tool === 'inpaint') return state.inpaintEraseStroke ? 'Erase mask' : 'Paint mask';
|
| return 'Stroke';
|
| }
|
|
|
| export function createStrokeTool({
|
| saveState, strokeTo, composite,
|
| getActiveMaskLayer, activeParentLayer, ensureActiveMaskLayer, createLayer,
|
| renderLayerPanel, syncToolClearIndicators,
|
| }) {
|
| return {
|
| |
| |
| |
|
|
| tryBegin(e) {
|
| if (!STROKE_TOOLS.has(state.tool)) return false;
|
|
|
|
|
|
|
| if (state.tool === 'inpaint') {
|
| const flip = e && e.ctrlKey && e.altKey;
|
| state.inpaintEraseStroke = flip ? !state.inpaintEraseMode : state.inpaintEraseMode;
|
|
|
|
|
|
|
| if (!getActiveMaskLayer()) {
|
| let parent = activeParentLayer();
|
| if (!parent) {
|
| parent = createLayer('Layer 1', state.imgWidth, state.imgHeight);
|
| state.layers.push(parent);
|
| state.activeLayerId = parent.id;
|
| }
|
| if (parent.masks && parent.masks.length) {
|
| parent.activeMaskId = parent.masks[parent.masks.length - 1].id;
|
| const m = getActiveMaskLayer();
|
| if (m) {
|
| state.maskCanvas = m.canvas;
|
| state.maskCtx = m.ctx;
|
| renderLayerPanel();
|
| }
|
| } else {
|
| const mk = ensureActiveMaskLayer();
|
| if (mk) {
|
| state.maskCanvas = mk.canvas;
|
| state.maskCtx = mk.ctx;
|
| renderLayerPanel();
|
| }
|
| }
|
| }
|
| }
|
| saveState(strokeLabel(state.tool));
|
| state.drawing = true;
|
| const coords = canvasCoords(e, state.mainCanvas);
|
| state.lastX = coords.x;
|
| state.lastY = coords.y;
|
| strokeTo(coords.x, coords.y);
|
| return true;
|
| },
|
|
|
| |
| |
| |
|
|
| tryContinue(e) {
|
| if (!state.drawing) return false;
|
| e.preventDefault();
|
| const coords = canvasCoords(e, state.mainCanvas);
|
| strokeTo(coords.x, coords.y);
|
| return true;
|
| },
|
|
|
| |
| |
|
|
| tryEnd() {
|
| if (!state.drawing) return false;
|
| const wasDrawingInpaint = state.tool === 'inpaint';
|
| state.drawing = false;
|
| composite();
|
| if (wasDrawingInpaint) syncToolClearIndicators();
|
| return true;
|
| },
|
| };
|
| }
|
|
|