M src/vier.nim => src/vier.nim +60 -4
@@ 81,6 81,7 @@ type
command: string
mode: Mode
tool: Tool
+ clipboard: seq[PixelChange]
const
backgroundColor0 = color"#555555"
@@ 298,6 299,7 @@ proc injectColor(picture: Picture, color: Color) =
)
picture.add(change)
picture.apply(change)
+ picture.selection.setLen(0)
proc addColor(picture: Picture, color: Color) =
## Adds the given color to all selected pixels.
@@ 317,10 319,11 @@ proc addColor(picture: Picture, color: Color) =
)
picture.add(change)
picture.apply(change)
+ picture.selection.setLen(0)
proc clickPixel(picture: Picture, target: Vec, mode: Mode, tool: Tool, color: Color) =
## Reacts to clicking the image at the given point or pressing spacebar with the cursor on it.
- picture.selection = @[]
+ picture.selection.setLen(0)
picture.anchor = target
case mode
of mInject:
@@ 510,6 513,36 @@ proc swapColors(app: App) =
swap(app.selectedPaletteIndex, app.secondaryColorPos.palette)
app.selectedPalette.cursor = cursor
+proc copy(app: App) =
+ let selection = app.selectedPicture.selection
+ let xMin = selection.mapIt(it.x).min()
+ let yMin = selection.mapIt(it.y).min()
+ app.clipboard =
+ collect:
+ for pixel in selection:
+ PixelChange(pos: pixel - (xMin, yMin), newColor: app.selectedPicture[pixel])
+ app.selectedPicture.selection.setLen(0)
+
+proc paste(app: App) =
+ let picture = app.selectedPicture
+ let cursor = picture.cursor
+ let
+ change =
+ ImageChange(
+ pixelChanges:
+ collect(
+ for pixel in app.clipboard:
+ if cursor + pixel.pos < picture.image.size:
+ PixelChange(
+ pos: cursor + pixel.pos,
+ originalColor: picture[pixel.pos],
+ newColor: pixel.newColor,
+ )
+ )
+ )
+ picture.add(change)
+ picture.apply(change)
+
proc ensureNonEmptyPictures(app: App) =
## Ensures that the app has at least one picture.
## Should be called whenever there is a possibility that the app has no pictures.
@@ 594,8 627,13 @@ proc processKeyboard(app: App) =
while (var ch = getCharPressed(); ch != 0):
app.command.add(Rune(ch))
else:
+ if isKeyPressed(Escape):
+ app.selectedPicture.selection.setLen(0)
if isKeyPressed(A):
- app.mode = mAdd
+ if app.selectedPicture.selection.len == 0:
+ app.mode = mAdd
+ else:
+ app.selectedPicture.addColor(app.color)
if isKeyPressed(B):
app.tool = Tool(kind: tBrush)
if isKeyPressed(C):
@@ 619,7 657,12 @@ proc processKeyboard(app: App) =
if isKeyPressed(F):
app.tool = Tool(kind: tFlood)
if isKeyPressed(I):
- app.mode = mInject
+ if app.selectedPicture.selection.len == 0:
+ app.mode = mInject
+ else:
+ app.selectedPicture.injectColor(app.color)
+ if isKeyPressed(P):
+ app.paste()
if isKeyPressed(Q):
if shift or app.pictures.all(isSaved):
closeWindow()
@@ 645,7 688,10 @@ proc processKeyboard(app: App) =
if isKeyPressed(X):
app.swapColors()
if isKeyPressed(Y):
- app.color = app.selectedPicture.colorAtCursor
+ if app.selectedPicture.selection.len == 0:
+ app.color = app.selectedPicture.colorAtCursor
+ else:
+ app.copy()
if isKeyPressed(Semicolon):
app.mode = mCommand
app.command = ""
@@ 812,6 858,16 @@ proc addApi(spry: var spryvm.Interpreter, app: App) =
nimFunc("new"):
app.pictures.add(newPicture())
app.selectedPictureIndex = app.pictures.high
+ nimFunc("resize"):
+ let widthNode = spry.evalArg()
+ let heightNode = spry.evalArg()
+ if widthNode of IntVal and heightNode of IntVal:
+ let width = widthNode.IntVal.value.int32
+ let height = heightNode.IntVal.value.int32
+ app.selectedPicture.image.imageResizeCanvas(width, height, 0, 0, Blank)
+ app.selectedPicture.loadTexture()
+ else:
+ raiseRuntimeException("Dimensions must be integers")
nimFunc("resize-nn"):
let widthNode = spry.evalArg()
let heightNode = spry.evalArg()
M website/index.html => website/index.html +13 -8
@@ 31,17 31,16 @@ nimble <span class="token function">install</span>
<section><h2 class="xd-section-heading">Keyboard mappings</h2><p>The key mappings are inspired by Vim. They are currently not customizable.</p>
<table><tr><th>Key</th><th>Alone</th><th>Shift</th><th>Control</th></tr>
<tr><td><kbd>⎵</kbd></td><td>hold to draw</td><td>hold to draw with secondary color</td></tr>
-<tr><td><kbd>A</kbd></td><td>Mode ← Add / add to selection</td></tr>
+<tr><td><kbd>A</kbd></td><td>Mode ← Add</td></tr>
<tr><td><kbd>B</kbd></td><td>Tool ← Brush</td></tr>
<tr><td><kbd>C</kbd></td><td>Mode ← Color</td></tr>
-<tr><td><kbd>D</kbd></td><td>delete pixel / delete selection</td></tr>
+<tr><td><kbd>D</kbd></td><td>delete pixel</td></tr>
<tr><td><kbd>F</kbd></td><td>Tool ← Flood</td></tr>
<tr><td><kbd>H</kbd></td><td>move left</td><td></td><td>previous picture/palette</td></tr>
-<tr><td><kbd>I</kbd></td><td>Mode ← Inject / fill selection</td></tr>
+<tr><td><kbd>I</kbd></td><td>Mode ← Inject</td></tr>
<tr><td><kbd>J</kbd></td><td>move down</td><td></td></tr>
<tr><td><kbd>K</kbd></td><td>move up</td><td></td></tr>
<tr><td><kbd>L</kbd></td><td>move right</td><td></td><td>next picture/palette</td></tr>
-<tr><td><kbd>M</kbd></td><td>Tool ← Mirror / cut selection</td></tr>
<tr><td><kbd>P</kbd></td><td>paste</td></tr>
<tr><td><kbd>Q</kbd></td><td>quit</td><td>force quit</td></tr>
<tr><td><kbd>R</kbd></td><td>Tool ← Rectangle</td><td></td><td>redo</td></tr>
@@ 50,14 49,20 @@ nimble <span class="token function">install</span>
<tr><td><kbd>V</kbd></td><td>Mode ← Select</td></tr>
<tr><td><kbd>W</kbd></td><td>write picture</td><td>write all pictures</td></tr>
<tr><td><kbd>X</kbd></td><td>swap colors</td></tr>
-<tr><td><kbd>Y</kbd></td><td>pick color / copy selection</td><td>pick secondary color</td></tr>
+<tr><td><kbd>Y</kbd></td><td>pick color</td><td>pick secondary color</td></tr>
<tr><td><kbd>-</kbd></td><td>zoom out</td><td>zoom out all pictures</td></tr>
<tr><td><kbd>=</kbd></td><td>zoom in</td><td>zoom in all pictures</td></tr>
<tr><td><kbd>;</kbd></td><td>Mode ← Command</td></tr></table>
-Note that the mouse can also be used to draw and select colors. The right mouse button draws with the secondary color.</section>
-<section><h2 class="xd-section-heading">Commands</h2><dl><dt><code>e image.png</code></dt><dd>open a file for editing (the filename is a symbol)</dd><dt><code>edit "image.png"</code></dt><dd>open a file for editing (the filename is a string)</dd><dt><code>flip-x</code></dt><dd>flip the current picture horizontally</dd><dt><code>flip-y</code></dt><dd>flip the current picture vertically</dd><dt><code>new</code></dt><dd>create a new picture with a transparent background and the default size</dd><dt><code>resize-nn 16 8</code></dt><dd>resize the current picture using the nearest-neighbor algorithm</dd><dt><code>w image.png</code></dt><dd>save the current picture under the specified filename (the filename is a symbol)</dd><dt><code>write "image.png"</code></dt><dd>save the current picture under the specified filename (the filename is a string)</dd></dl>
+Note that the mouse can also be used to draw and select colors. The right mouse button draws with the secondary color.
+<section><h3 class="xd-section-heading">Selection keyboard mappings</h3><p>Some keys work differently when used with an active selection.</p>
+<table><tr><th>Key</th><th>Alone</th><th>Shift</th><th>Control</th></tr>
+<tr><td><kbd>Esc</kbd></td><td>cancel selection</td></tr>
+<tr><td><kbd>A</kbd></td><td>add selected color on selection</td></tr>
+<tr><td><kbd>I</kbd></td><td>fill selection with selected color</td></tr>
+<tr><td><kbd>Y</kbd></td><td>copy selection</td></tr></table></section></section>
+<section><h2 class="xd-section-heading">Commands</h2><dl><dt><code>e image.png</code></dt><dd>open a file for editing (the filename is a symbol)</dd><dt><code>edit "image.png"</code></dt><dd>open a file for editing (the filename is a string)</dd><dt><code>flip-x</code></dt><dd>flip the current picture horizontally</dd><dt><code>flip-y</code></dt><dd>flip the current picture vertically</dd><dt><code>new</code></dt><dd>create a new picture with a transparent background and the default size</dd><dt><code>resize 16 8</code></dt><dd>resize the current picture, anchoring at the northwest corner</dd><dt><code>resize-nn 16 8</code></dt><dd>resize the current picture using the nearest-neighbor algorithm</dd><dt><code>w image.png</code></dt><dd>save the current picture under the specified filename (the filename is a symbol)</dd><dt><code>write "image.png"</code></dt><dd>save the current picture under the specified filename (the filename is a string)</dd></dl>
<p>Note that currently, edits done via commands are not added to undo history and break it.</p></section>
<section><h2 class="xd-section-heading">Planned features</h2><p>Roughly in order of priority.</p>
-<ul><li>copy/paste functionality for the select mode</li><li>ellipse tool</li><li>eyedropper tool</li><li>upscaling (various algorithms)</li><li>better editing support and tab completion for the command line</li><li>mirrored drawing</li><li>color picker, palette editing</li><li>programmable configuration</li><li>gradients</li><li>animated sprite editing</li></ul></section>
+<ul><li>ellipse tool</li><li>upscaling (various algorithms)</li><li>better editing support and tab completion for the command line</li><li>mirrored drawing</li><li>color picker, palette editing</li><li>programmable configuration</li><li>gradients</li><li>animated sprite editing</li></ul></section>
<section><h2 class="xd-section-heading">Name</h2><p>I partially created Vier as a semestral project for a Computer Graphics course at my university. The name of the lecturer can be loosely translated as “fear”, so I decided to name the project after a German word which is pronounced the same way. The word means “four”, which hints at the editor treating images as a square grid (with squares having four sides, obviously). I also came up with the backronym “Vim-Inspired Editor of Rasters”.</p></section>
</body></html>=
\ No newline at end of file
M website/index.xd => website/index.xd +18 -7
@@ 60,18 60,18 @@
[table
[header-row Key; Alone; Shift; Control]
[row [<kbd> ⎵]; hold to draw; hold to draw with secondary color]
- [row [<kbd> A]; Mode ← Add / add to selection]
+ [row [<kbd> A]; Mode ← Add]
[row [<kbd> B]; Tool ← Brush]
[row [<kbd> C]; Mode ← Color]
- [row [<kbd> D]; delete pixel / delete selection]
+ [row [<kbd> D]; delete pixel]
[# row [<kbd> E]; Tool ← Ellipse]
[row [<kbd> F]; Tool ← Flood]
[row [<kbd> H]; move left; [# move to left edge]; previous picture/palette]
- [row [<kbd> I]; Mode ← Inject / fill selection]
+ [row [<kbd> I]; Mode ← Inject]
[row [<kbd> J]; move down; [# move to bottom edge]]
[row [<kbd> K]; move up; [# move to top edge]]
[row [<kbd> L]; move right; [# move to right edge]; next picture/palette]
- [row [<kbd> M]; Tool ← Mirror / cut selection]
+ [# row [<kbd> M]; Tool ← Mirror]
[row [<kbd> P]; paste]
[row [<kbd> Q]; quit; force quit]
[row [<kbd> R]; Tool ← Rectangle; ; redo]
@@ 80,12 80,24 @@
[row [<kbd> V]; Mode ← Select]
[row [<kbd> W]; write picture; write all pictures]
[row [<kbd> X]; swap colors]
- [row [<kbd> Y]; pick color / copy selection; pick secondary color]
+ [row [<kbd> Y]; pick color; pick secondary color]
[row [<kbd> -]; zoom out; zoom out all pictures]
[row [<kbd> =]; zoom in; zoom in all pictures]
[row [<kbd> [;]]; Mode ← Command]
]
Note that the mouse can also be used to draw and select colors. The right mouse button draws with the secondary color.
+ [section Selection keyboard mappings;
+ [p Some keys work differently when used with an active selection.]
+ [table
+ [header-row Key; Alone; Shift; Control]
+ [row [<kbd> Esc]; cancel selection]
+ [row [<kbd> A]; add selected color on selection]
+ [# row [<kbd> D]; delete selection]
+ [row [<kbd> I]; fill selection with selected color]
+ [# row [<kbd> M]; cut selection]
+ [row [<kbd> Y]; copy selection]
+ ]
+ ]
]
[section Commands;
[description-list
@@ 94,6 106,7 @@
; [code flip-x]; flip the current picture horizontally
; [code flip-y]; flip the current picture vertically
; [code new]; create a new picture with a transparent background and the default size
+ ; [code resize 16 8]; resize the current picture, anchoring at the northwest corner
; [code resize-nn 16 8]; resize the current picture using the nearest-neighbor algorithm
; [code w image.png]; save the current picture under the specified filename (the filename is a symbol)
; [code write "image.png"]; save the current picture under the specified filename (the filename is a string)
@@ 103,9 116,7 @@
[section Planned features;
[p Roughly in order of priority.]
[list
- ; copy/paste functionality for the select mode
; ellipse tool
- ; eyedropper tool
; upscaling (various algorithms)
; better editing support and tab completion for the command line
; mirrored drawing