Add some magic

main
kts of kettek 2024-02-17 22:46:47 -08:00
parent 7cce4f2fbd
commit 6bbb473784
2 changed files with 58 additions and 2 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, Move } from "carbon-icons-svelte"
import { Close, Erase, PaintBrushAlt, RainDrop, Redo, Select_01, Undo, Scale, Eyedropper, Move, MagicWand } 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, MoveTool } from './types/tools'
import { BrushTool, EraserTool, FillTool, PickerTool, SelectionTool, MagicWandTool, 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'
@ -51,6 +51,7 @@
let showPreview: boolean = false
let toolSelection = new SelectionTool()
let toolMagicWand = new MagicWandTool()
let toolFill = new FillTool()
let toolErase = new EraserTool()
let toolBrush = new BrushTool()
@ -147,6 +148,7 @@
<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 === toolMagicWand} kind="ghost" size="small" icon={MagicWand} iconDescription="magic selection" tooltipPosition="right" on:click={()=>swapTool(toolMagicWand)}></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>
<Button isSelected={currentTool === toolPicker} kind="ghost" size="small" icon={Eyedropper} iconDescription="pick" tooltipPosition="right" on:click={()=>swapTool(toolPicker)}></Button>
@ -154,6 +156,7 @@
<Shortcuts group='editor2D'>
<Shortcut global cmd='clear selection' keys={['escape']} on:trigger={()=>focusedFile?.push(new SelectionClearUndoable())} />
<Shortcut global cmd='selection' keys={['s']} on:trigger={()=>swapTool(toolSelection)} />
<Shortcut global cmd='magic selection' keys={['shift+s']} on:trigger={()=>swapTool(toolMagicWand)} />
<Shortcut global cmd='move' keys={['m']} on:trigger={()=>swapTool(toolMove)} />
<Shortcut global cmd='move left' keys={['arrowleft']} on:trigger={()=>toolMove.shift({file: focusedFile}, {x: -1, y: 0, id: 0})} />
<Shortcut global cmd='move right' keys={['arrowright']} on:trigger={()=>toolMove.shift({file: focusedFile}, {x: 1, y: 0, id: 0})} />

View File

@ -282,6 +282,59 @@ export class SelectionTool implements Tool {
}
}
export class MagicWandTool implements Tool {
private active: boolean
isActive(): boolean {
return this.active
}
pointerDown(ctx: ToolContext & FloodToolContext, ptr: Pointer) {
this.active = true
let pixels: { x: number, y: number, marked: boolean }[] = []
let traversed = new Set<number>()
let value = true
let clear = false
if (!ptr.shift && !ptr.control) {
clear = true
}
if (ptr.control) {
value = false
}
let p = ctx.file.canvas.getPixel(ptr.x, ptr.y)
if (p !== -1) {
let queue = [{x: ptr.x, y: ptr.y}]
while (queue.length > 0) {
let {x, y} = queue.shift()
let index = y * ctx.file.canvas.width + x
if (traversed.has(index)) {
continue
}
traversed.add(index)
let p2 = ctx.file.canvas.getPixel(x, y)
if (p2 === p) {
pixels.push({x, y, marked: value})
if (x > 0) queue.push({x: x-1, y})
if (x < ctx.file.canvas.width-1) queue.push({x: x+1, y})
if (y > 0) queue.push({x, y: y-1})
if (y < ctx.file.canvas.height-1) queue.push({x, y: y+1})
}
}
}
ctx.file.selection.active = true
ctx.file.push(new SelectionSetUndoable(pixels, clear))
}
pointerMove(ctx: ToolContext & FloodToolContext, ptr: Pointer) {
}
pointerUp(ctx: ToolContext & FloodToolContext, ptr: Pointer) {
this.active = false
}
}
export class MoveTool implements Tool {
private active: boolean
private startX: number