Add dubious move tool

main
kts of kettek 2024-02-16 22:53:15 -08:00
parent 32beb3a221
commit 381d435fd7
3 changed files with 61 additions and 3 deletions

View File

@ -14,10 +14,10 @@
import { OverflowMenu, OverflowMenuItem } from "carbon-components-svelte"
import { Close, Erase, PaintBrushAlt, RainDrop, Redo, Select_01, Undo, Scale, Eyedropper } from "carbon-icons-svelte"
import { Close, Erase, PaintBrushAlt, RainDrop, Redo, Select_01, Undo, Scale, Eyedropper, Move } from "carbon-icons-svelte"
import StackPreview from './sections/StackPreview.svelte'
import type { Canvas } from './types/canvas'
import { BrushTool, EraserTool, FillTool, PickerTool, SelectionTool, type BrushType, type Tool } from './types/tools'
import { BrushTool, EraserTool, FillTool, PickerTool, SelectionTool, type BrushType, type Tool, MoveTool } from './types/tools'
import BrushSize from './components/BrushSize.svelte'
import Shortcut from './components/Shortcut.svelte'
import Shortcuts from './components/Shortcuts.svelte'
@ -41,6 +41,7 @@
let toolErase = new EraserTool()
let toolBrush = new BrushTool()
let toolPicker = new PickerTool()
let toolMove = new MoveTool()
let currentTool: Tool = toolBrush
let previousTool: Tool = null
let brushSize: number = 1
@ -110,6 +111,7 @@
<PaletteSection bind:palette bind:primaryColorIndex bind:secondaryColorIndex file={focusedFile} />
</section>
<menu class='toolbar'>
<Button isSelected={currentTool === toolMove} kind="ghost" size="small" icon={Move} iconDescription="move" tooltipPosition="right" on:click={()=>swapTool(toolMove)}></Button>
<Button isSelected={currentTool === toolSelection} kind="ghost" size="small" icon={Select_01} iconDescription="selection" tooltipPosition="right" on:click={()=>swapTool(toolSelection)}></Button>
<Button isSelected={currentTool === toolFill} kind="ghost" size="small" icon={RainDrop} iconDescription="fill" tooltipPosition="right" on:click={()=>swapTool(toolFill)}></Button>
<Button isSelected={currentTool === toolBrush} kind="ghost" size="small" icon={PaintBrushAlt} iconDescription="paint" tooltipPosition="right" on:click={()=>swapTool(toolBrush)}></Button>
@ -117,6 +119,7 @@
<Button isSelected={currentTool === toolErase} kind="ghost" size="small" icon={Erase} iconDescription="erase" tooltipPosition="right" on:click={()=>swapTool(toolErase)}></Button>
<Shortcuts group='editor2D'>
<Shortcut global cmd='selection' keys={['s']} on:trigger={()=>swapTool(toolSelection)} />
<Shortcut global cmd='move' keys={['m']} on:trigger={()=>swapTool(toolMove)} />
<Shortcut global cmd='brush' keys={['b']} on:trigger={()=>swapTool(toolBrush)} />
<Shortcut global cmd='brushToPicker' keys={['alt']} on:trigger={()=>currentTool===toolBrush?swapTool(toolPicker):null} on:release={()=>previousTool===toolBrush&&currentTool===toolPicker?swapTool(toolBrush):null} />
<Shortcut global cmd='fill' keys={['f']} on:trigger={()=>swapTool(toolFill)} />

View File

@ -4,7 +4,7 @@
import type { data } from '../../wailsjs/go/models.ts'
import type { LoadedFile } from '../types/file'
import { FilledCircle, FilledSquare, type PixelPosition } from '../types/shapes'
import { BrushTool, EraserTool, FillTool, PickerTool, type BrushType, type Tool, SelectionTool } from '../types/tools'
import { BrushTool, EraserTool, FillTool, PickerTool, MoveTool, type BrushType, type Tool, SelectionTool } from '../types/tools'
import { Button, NumberInput, OverflowMenu, OverflowMenuItem, Slider } from 'carbon-components-svelte';
import { ZoomIn, ZoomOut } from 'carbon-icons-svelte';

View File

@ -274,6 +274,61 @@ export class SelectionTool implements Tool {
}
}
this.active = false
}
}
export class MoveTool implements Tool {
private active: boolean
private startX: number
private startY: number
private endX: number
private endY: number
isActive(): boolean {
return this.active
}
pointerDown(ctx: ToolContext, ptr: Pointer) {
this.startX = this.endX = ptr.x
this.startY = this.endY = ptr.y
this.active = true
}
pointerMove(ctx: ToolContext, ptr: Pointer) {
this.endX = ptr.x
this.endY = ptr.y
}
pointerUp(ctx: ToolContext, ptr: Pointer) {
if (this.startX === this.endX && this.startY === this.endY) {
this.active = false
return
}
let dx = this.endX - this.startX
let dy = this.endY - this.startY
let pixels: { x: number, y: number, index: number }[] = []
let clearPixels: { x: number, y: number, index: number }[] = []
for (let x = 0; x < ctx.file.canvas.width; x++) {
for (let y = 0; y < ctx.file.canvas.height; y++) {
if (ctx.file.selection.isPixelMarked(x, y)) {
let p = ctx.file.canvas.getPixel(x, y)
let { a } = ctx.file.canvas.getPaletteAsRGBA(p)
// FIXME: Do we really want to treat 0 as transparent index? Additionally, for RGBA, we probably want to merge the colors and create a new entry... maybe this should be handled in PixelsPlaceUndoable within the file class...
if (a !== 0) {
if (x+dx >= 0 && x+dx < ctx.file.canvas.width && y+dy >= 0 && y+dy < ctx.file.canvas.height) {
pixels.push({x: x+dx, y: y+dy, index: p})
}
clearPixels.push({x, y, index: 0})
}
}
}
}
ctx.file.capture()
ctx.file.push(new PixelsPlaceUndoable(clearPixels))
ctx.file.push(new PixelsPlaceUndoable(pixels))
ctx.file.release()
this.active = false
}
}