A .reuse/dep5 => .reuse/dep5 +12 -0
@@ 0,0 1,12 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: Vier
+Upstream-Contact: Adam Blažek <blazead5@cvut.cz>
+Source: https://git.sr.ht/~xigoi/vier
+
+Files: assets/icons/*
+Copyright: Adam Blažek <blazead5@cvut.cz>
+License: GPL-3.0-or-later
+
+Files: website/assets/icons/*
+Copyright: Adam Blažek <blazead5@cvut.cz>
+License: GPL-3.0-or-later
M README.md => README.md +5 -0
@@ 1,3 1,8 @@
+<!--
+ © 2023 Adam Blažek <blazead5@cvut.cz>
+ SPDX-License-Identifier: GPL-3.0-or-later
+-->
+
# vier
_Vier_ is a keyboard-focused pixel art editor heavily inspired by Vim.
D assets/icons/modes/color.png.license => assets/icons/modes/color.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
D assets/icons/modes/command.png.license => assets/icons/modes/command.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
D assets/icons/modes/inject.png.license => assets/icons/modes/inject.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
D assets/icons/modes/select.png.license => assets/icons/modes/select.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
D assets/icons/template.png.license => assets/icons/template.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
D assets/icons/tools/brush.png.license => assets/icons/tools/brush.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
A assets/icons/tools/ellipse-filled.png => assets/icons/tools/ellipse-filled.png +0 -0
R assets/icons/tools/ellipse.png => assets/icons/tools/ellipse-outline.png +0 -0
D assets/icons/tools/flood.png.license => assets/icons/tools/flood.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
R assets/icons/tools/rectangle.png => assets/icons/tools/rectangle-filled.png +0 -0
A assets/icons/tools/rectangle-outline.png => assets/icons/tools/rectangle-outline.png +0 -0
D assets/icons/tools/rectangle.png.license => assets/icons/tools/rectangle.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
D assets/icons/tools/segment.png.license => assets/icons/tools/segment.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
M scripts/upload.fish => scripts/upload.fish +2 -0
@@ 1,4 1,6 @@
#!/usr/bin/env fish
+# © 2023 Adam Blažek <blazead5@cvut.cz>
+# SPDX-License-Identifier: GPL-3.0-or-later
tar -cvz -C website . -f site.tar.gz
hut pages publish -d xigoi.srht.site -s vier site.tar.gz
rm site.tar.gz
M src/vector.nim => src/vector.nim +6 -0
@@ 44,6 44,12 @@ func `>=`*(u, v: Vec): bool =
func abs*(u: Vec): Vec =
(abs(u.x), abs(u.y))
+func min*(u, v: Vec): Vec =
+ (min(u.x, v.x), min(u.y, v.y))
+
+func max*(u, v: Vec): Vec =
+ (max(u.x, v.x), max(u.y, v.y))
+
func square*(n: int32): Vec =
(n, n)
M src/vier.nim => src/vier.nim +105 -69
@@ 18,32 18,28 @@ import std/unicode
type
Mode = enum
- mInject = "Inject"
- mAdd = "Add"
- mSelect = "Select"
- mColor = "Color"
- mCommand = "Command"
+ Inject
+ Add
+ Select
+ Color
+ Command
ToolKind = enum
- tBrush = "Brush"
- tFlood = "Flood"
- tRect = "Rect"
- tSegment = "Segment"
- tEllipse = "Ellipse"
-
- ShapeMode = enum
- rFilled
- rOutline
+ Brush
+ Flood
+ Segment
+ RectFilled
+ RectOutline
+ EllipseFilled
+ EllipseOutline
Tool = object
case kind: ToolKind
- of tBrush:
+ of Brush:
brushSize: int32 # ignored for now
- of tFlood:
+ of Flood:
tolerance: int32
- of tRect, tEllipse:
- shapeMode: ShapeMode # ignored for now
- of tSegment:
+ else:
discard
PixelChange = object
@@ 105,18 101,20 @@ var modeIcons: array[Mode, Texture]
var toolIcons: array[ToolKind, Texture]
proc loadIcons() =
modeIcons = [
- mInject: loadTextureStatic("icons/modes/inject.png"),
- mAdd: loadTextureStatic("icons/modes/add.png"),
- mSelect: loadTextureStatic("icons/modes/select.png"),
- mColor: loadTextureStatic("icons/modes/color.png"),
- mCommand: loadTextureStatic("icons/modes/command.png")
+ Inject: loadTextureStatic("icons/modes/inject.png"),
+ Add: loadTextureStatic("icons/modes/add.png"),
+ Select: loadTextureStatic("icons/modes/select.png"),
+ Color: loadTextureStatic("icons/modes/color.png"),
+ Command: loadTextureStatic("icons/modes/command.png")
]
toolIcons = [
- tBrush: loadTextureStatic("icons/tools/brush.png"),
- tFlood: loadTextureStatic("icons/tools/flood.png"),
- tRect: loadTextureStatic("icons/tools/rectangle.png"),
- tSegment: loadTextureStatic("icons/tools/segment.png"),
- tEllipse: loadTextureStatic("icons/tools/ellipse.png")
+ Brush: loadTextureStatic("icons/tools/brush.png"),
+ Flood: loadTextureStatic("icons/tools/flood.png"),
+ Segment: loadTextureStatic("icons/tools/segment.png"),
+ RectFilled: loadTextureStatic("icons/tools/rectangle-filled.png"),
+ RectOutline: loadTextureStatic("icons/tools/rectangle-outline.png"),
+ EllipseFilled: loadTextureStatic("icons/tools/ellipse-filled.png"),
+ EllipseOutline: loadTextureStatic("icons/tools/ellipse-outline.png")
]
proc loadTexture(picture: Picture) =
@@ 247,7 245,35 @@ proc lineSegment(start, `end`: Vec, includeStart: bool): seq[Vec] =
point.y += signY
result.add(point)
-proc ellipse(a, b: Vec): seq[Vec] =
+proc rectangleFilled(a, b: Vec): seq[Vec] =
+ collect:
+ for y in min(a.y, b.y)..max(a.y, b.y):
+ for x in min(a.x, b.x)..max(a.x, b.x):
+ (x, y)
+
+proc rectangleOutline(a, b: Vec): seq[Vec] =
+ let u = min(a, b)
+ let v = max(a, b)
+ concat(
+ collect(
+ for x in u.x..v.x:
+ (x, u.y)
+ ),
+ collect(
+ for x in u.x..v.x:
+ (x, v.y)
+ ),
+ collect(
+ for y in u.y + 1..v.y - 1:
+ (u.x, y)
+ ),
+ collect(
+ for y in u.y + 1..v.y - 1:
+ (v.x, y)
+ ),
+ )
+
+proc ellipse(a, b: Vec, filled: bool): seq[Vec] =
# Algorithm taken from http://members.chello.at/easyfilter/bresenham.pdf
var
a = a
@@ 267,7 293,10 @@ proc ellipse(a, b: Vec): seq[Vec] =
a.y += (diameter.y + 1) div 2
b.y = a.y - parity
while a.x <= b.x:
- result.add([(a.x, a.y), (b.x, a.y), (a.x, b.y), (b.x, b.y)])
+ if filled:
+ result.add(rectangleOutline(a, b))
+ else:
+ result.add([(a.x, a.y), (b.x, a.y), (a.x, b.y), (b.x, b.y)])
let doubleError = 2 * error
if doubleError <= errorIncrement.y:
a.y.inc()
@@ 283,10 312,12 @@ proc ellipse(a, b: Vec): seq[Vec] =
result.add([(a.x - 1, a.y), (b.x + 1, a.y), (a.x - 1, b.y), (b.x + 1, b.y)])
a.y.inc()
b.y.dec()
+ if filled:
+ result = toSeq(toHashSet(result))
proc select(picture: Picture, target: Vec, tool: Tool) =
case tool.kind
- of tBrush:
+ of Brush:
# TODO: brush size
if picture.selection.len == 0:
picture.selection.add(target)
@@ 294,7 325,7 @@ proc select(picture: Picture, target: Vec, tool: Tool) =
picture.selection.add(
lineSegment(picture.selection[^1], target, includeStart = false)
)
- of tFlood:
+ of Flood:
var stack = @[target]
var toSelect = initHashSet[Vec]()
while stack.len != 0:
@@ 316,16 347,16 @@ proc select(picture: Picture, target: Vec, tool: Tool) =
if pos.y < picture.image.height - 1:
check(pos.x, pos.y + 1)
picture.selection = toSelect.toSeq()
- of tRect:
- picture.selection =
- collect:
- for y in min(picture.anchor.y, target.y)..max(picture.anchor.y, target.y):
- for x in min(picture.anchor.x, target.x)..max(picture.anchor.x, target.x):
- (x, y)
- of tSegment:
+ of RectFilled:
+ picture.selection = rectangleFilled(picture.anchor, target)
+ of RectOutline:
+ picture.selection = rectangleOutline(picture.anchor, target)
+ of Segment:
picture.selection = lineSegment(picture.anchor, target, includeStart = true)
- of tEllipse:
- picture.selection = ellipse(picture.anchor, target)
+ of EllipseFilled:
+ picture.selection = ellipse(picture.anchor, target, filled = true)
+ of EllipseOutline:
+ picture.selection = ellipse(picture.anchor, target, filled = false)
proc injectColor(picture: Picture, color: Color) =
## Changes all selected pixels to the given color.
@@ 365,32 396,32 @@ proc clickPixel(picture: Picture, target: Vec, mode: Mode, tool: Tool, color: Co
picture.selection.setLen(0)
picture.anchor = target
case mode
- of mInject:
+ of Inject:
picture.select(target, tool)
picture.injectColor(color)
- of mAdd:
+ of Add:
picture.select(target, tool)
picture.addColor(color)
- of mSelect:
+ of Select:
picture.select(target, tool)
- of mColor, mCommand:
+ of Color, Command:
discard
proc dragPixel(picture: Picture, target: Vec, mode: Mode, tool: Tool, color: Color) =
## Reacts to dragging the mouse over the given point with the mouse button held down,
## or to moving the cursor over the point while holding spacebar.
case mode
- of mInject:
+ of Inject:
picture.select(target, tool)
picture.undo()
picture.injectColor(color)
- of mAdd:
+ of Add:
picture.select(target, tool)
picture.undo()
picture.addColor(color)
- of mSelect:
+ of Select:
picture.select(target, tool)
- of mColor, mCommand:
+ of Color, Command:
discard
proc isSaved(picture: Picture): bool =
@@ 461,7 492,7 @@ proc draw(picture: Picture, app: App, origin: Vec, selected: bool) =
canvasSize.x,
if picture.isSaved: White else: unsavedNameColor,
)
- if app.mode == mSelect:
+ if app.mode == Select:
for pixel in picture.selection:
drawRectangle(
origin + picture.scale * pixel, square(picture.scale), selectionInnerColor
@@ 559,7 590,7 @@ proc clearSelection(app: App) =
app.selectedPicture.clearSelection()
proc activeSelection(app: App): bool =
- app.mode == mSelect and app.selectedPicture.selection.len != 0
+ app.mode == Select and app.selectedPicture.selection.len != 0
proc copy(app: App) =
let selection = app.selectedPicture.selection
@@ 651,12 682,12 @@ proc draw(app: App) =
proc processKeyboard(app: App) =
let shift = isKeyDown(LeftShift) or isKeyDown(RightShift)
let control = isKeyDown(LeftControl) or isKeyDown(RightControl)
- if app.mode == mCommand:
+ if app.mode == Command:
if isKeyPressed(Escape):
- app.mode = mInject
+ app.mode = Inject
app.command = ""
elif isKeyPressed(Enter):
- app.mode = mInject
+ app.mode = Inject
try:
let res = app.spry.eval("[" & app.command & "]")
if res.isNil or res of NilVal:
@@ 667,7 698,7 @@ proc processKeyboard(app: App) =
app.command = getCurrentExceptionMsg()
elif isKeyPressed(Backspace):
if app.command.len == 0:
- app.mode = mInject
+ app.mode = Inject
else:
app.command.setLen(app.command.len - 1)
else:
@@ 682,11 713,11 @@ proc processKeyboard(app: App) =
app.selectedPicture.addColor(app.color)
app.clearSelection()
else:
- app.mode = mAdd
+ app.mode = Add
if isKeyPressed(B):
- app.tool = Tool(kind: tBrush)
+ app.tool = Tool(kind: Brush)
if isKeyPressed(C):
- app.mode = mColor
+ app.mode = Color
if isKeyPressed(D):
let picture = app.selectedPicture
let
@@ 704,15 735,18 @@ proc processKeyboard(app: App) =
picture.add(change)
picture.apply(change)
if isKeyPressed(E):
- app.tool = Tool(kind: tEllipse)
+ if shift:
+ app.tool = Tool(kind: EllipseOutline)
+ else:
+ app.tool = Tool(kind: EllipseFilled)
if isKeyPressed(F):
- app.tool = Tool(kind: tFlood)
+ app.tool = Tool(kind: Flood)
if isKeyPressed(I):
if app.activeSelection:
app.selectedPicture.injectColor(app.color)
app.clearSelection()
else:
- app.mode = mInject
+ app.mode = Inject
if isKeyPressed(P):
app.paste()
if isKeyPressed(Q):
@@ 724,14 758,16 @@ proc processKeyboard(app: App) =
if isKeyPressed(R):
if control:
app.selectedPicture.redo
+ elif shift:
+ app.tool = Tool(kind: RectOutline)
else:
- app.tool = Tool(kind: tRect)
+ app.tool = Tool(kind: RectFilled)
if isKeyPressed(S):
- app.tool = Tool(kind: tSegment)
+ app.tool = Tool(kind: Segment)
if isKeyPressed(U):
app.selectedPicture.undo
if isKeyPressed(V):
- app.mode = mSelect
+ app.mode = Select
if isKeyPressed(W):
if shift:
app.pictures.apply(write)
@@ 746,7 782,7 @@ proc processKeyboard(app: App) =
else:
app.color = app.selectedPicture.colorAtCursor
if isKeyPressed(Semicolon):
- app.mode = mCommand
+ app.mode = Command
app.command = ""
while (var ch = getCharPressed(); ch != 0):
discard
@@ 771,7 807,7 @@ proc processKeyboard(app: App) =
movement = square(0)
app.movementTime.inc
case app.mode
- of mInject, mAdd, mSelect:
+ of Inject, Add, Select:
if movement != square(0):
if control:
app.selectedPictureIndex =
@@ 800,7 836,7 @@ proc processKeyboard(app: App) =
app.color
,
)
- of mColor:
+ of Color:
if movement != square(0):
if control:
app.selectedPaletteIndex =
@@ 809,7 845,7 @@ proc processKeyboard(app: App) =
else:
app.selectedPalette.moveCursor(movement)
app.updateColor()
- of mCommand:
+ of Command:
discard
proc processMouse(app: App) =
D website/assets/icons/modes/add.png.license => website/assets/icons/modes/add.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
D website/assets/icons/modes/color.png.license => website/assets/icons/modes/color.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
D website/assets/icons/modes/command.png.license => website/assets/icons/modes/command.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
D website/assets/icons/modes/inject.png.license => website/assets/icons/modes/inject.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
D website/assets/icons/modes/select.png.license => website/assets/icons/modes/select.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
D website/assets/icons/template.png.license => website/assets/icons/template.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
D website/assets/icons/tools/brush.png.license => website/assets/icons/tools/brush.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
A website/assets/icons/tools/ellipse-filled.png => website/assets/icons/tools/ellipse-filled.png +0 -0
R assets/icons/template.png => website/assets/icons/tools/ellipse-outline.png +0 -0
D website/assets/icons/tools/flood.png.license => website/assets/icons/tools/flood.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
A website/assets/icons/tools/rectangle-filled.png => website/assets/icons/tools/rectangle-filled.png +0 -0
A website/assets/icons/tools/rectangle-outline.png => website/assets/icons/tools/rectangle-outline.png +0 -0
D website/assets/icons/tools/rectangle.png.license => website/assets/icons/tools/rectangle.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
D website/assets/icons/tools/segment.png.license => website/assets/icons/tools/segment.png.license +0 -2
@@ 1,2 0,0 @@
-© 2023 Adam Blažek <blazead5@cvut.cz>
-SPDX-License-Identifier: GPL-3.0-or-later
M website/index.html => website/index.html +3 -3
@@ 29,7 29,7 @@ nimble <span class="token function">install</span>
<p>Vier has these modes:</p>
<dl><dt><img src="assets/icons/modes/inject.png" alt="Inject mode icon" /> Inject mode</dt><dd>In this mode, the user can move around the selected picture using <kbd>H</kbd><kbd>J</kbd><kbd>K</kbd><kbd>L</kbd> keys and draw with the currently selected tool. The color of the pixels being drawn is replaced by the selected color, so this can also work as an “eraser” if the selected color is transparent. If multiple pictures are opened, they can be switched between using <kbd>Ctrl</kbd>-<kbd>H</kbd> and <kbd>Ctrl</kbd>-<kbd>L</kbd>.</dd><dt><img src="assets/icons/modes/add.png" alt="Add mode icon" /> Add mode</dt><dd>In this mode, the user can move around the selected picture using <kbd>H</kbd><kbd>J</kbd><kbd>K</kbd><kbd>L</kbd> keys and draw with the currently selected tool. The selected color is added on the color of the pixels being drawn, which allows shading an area with a transparent color. If multiple pictures are opened, they can be switched between using <kbd>Ctrl</kbd>-<kbd>H</kbd> and <kbd>Ctrl</kbd>-<kbd>L</kbd>.</dd><dt><img src="assets/icons/modes/select.png" alt="Select mode icon" /> Select mode</dt><dd>In this mode, the user can move around the selected picture using <kbd>H</kbd><kbd>J</kbd><kbd>K</kbd><kbd>L</kbd> keys and select a part of the picture using the currently selected tool. The selection is currently useless; copy-paste functionality will be implemented later. If multiple pictures are opened, they can be switched between using <kbd>Ctrl</kbd>-<kbd>H</kbd> and <kbd>Ctrl</kbd>-<kbd>L</kbd>.</dd><dt><img src="assets/icons/modes/color.png" alt="Color mode icon" /> Color mode</dt><dd>In this mode, the user can move around a color palette (displayed at the top of the screen) to change the selected color (displayed in the upper left corner). If multiple palettes are available, they can be switched between using <kbd>Ctrl</kbd>-<kbd>H</kbd> and <kbd>Ctrl</kbd>-<kbd>L</kbd>.</dd><dt><img src="assets/icons/modes/command.png" alt="Command mode icon" /> Command mode</dt><dd>In this mode, the user can enter a command, displayed at the bottom of the screen, to perform complex actions such as opening a file. The commands are in the <a href="https://sprylang.se/">Spry</a> programming language, though this is not important for basic usage. The command is executed by pressing <kbd>⏎</kbd> or cancelled by pressing <kbd>Esc</kbd>.</dd></dl>
<p>The following tools are available:</p>
-<dl><dt><img src="assets/icons/tools/brush.png" alt="Brush icon" /> Brush</dt><dd>The brush tool selects pixels that it moves over.</dd><dt><img src="assets/icons/tools/segment.png" alt="Segment icon" /> Segment</dt><dd>The segment tool selects a line segment.</dd><dt><img src="assets/icons/tools/rectangle.png" alt="Rectangle icon" /> Rectangle</dt><dd>The rectangle tool selects an axis-aligned rectangle.</dd><dt><img src="assets/icons/tools/ellipse.png" alt="Ellipse icon" /> Rectangle</dt><dd>The rectangle tool selects the outline of an axis-aligned ellipse.</dd><dt><img src="assets/icons/tools/flood.png" alt="Flood icon" /> Flood</dt><dd>The flood tool selects a contiguous area of pixels with the same color.</dd></dl></section>
+<dl><dt><img src="assets/icons/tools/brush.png" alt="Brush icon" /> Brush</dt><dd>The brush tool selects pixels that it moves over.</dd><dt><img src="assets/icons/tools/segment.png" alt="Segment icon" /> Segment</dt><dd>The segment tool selects a line segment.</dd><dt><img src="assets/icons/tools/rectangle-filled.png" alt="Rectangle icon" /> Rectangle</dt><dd>The rectangle tool selects an axis-aligned rectangle.</dd><dt><img src="assets/icons/tools/rectangle-outline.png" alt="Rectangle outline icon" /> Rectangle outline</dt><dd>The rectangle tool selects the outline of an axis-aligned rectangle.</dd><dt><img src="assets/icons/tools/ellipse-filled.png" alt="Ellipse icon" /> Ellipse</dt><dd>The ellipse tool selects an axis-aligned ellipse.</dd><dt><img src="assets/icons/tools/ellipse-outline.png" alt="Ellipse outline icon" /> Ellipse outline</dt><dd>The ellipse outline tool selects the outline of an axis-aligned ellipse.</dd><dt><img src="assets/icons/tools/flood.png" alt="Flood icon" /> Flood</dt><dd>The flood tool selects a contiguous area of pixels with the same color.</dd></dl></section>
<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>
@@ 37,7 37,7 @@ nimble <span class="token function">install</span>
<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</td></tr>
-<tr><td><kbd>E</kbd></td><td>Tool ← Ellipse</td></tr>
+<tr><td><kbd>E</kbd></td><td>Tool ← Ellipse</td><td>Tool ← Ellipse outline</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</td></tr>
@@ 46,7 46,7 @@ nimble <span class="token function">install</span>
<tr><td><kbd>L</kbd></td><td>move right</td><td></td><td>next picture/palette</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>
+<tr><td><kbd>R</kbd></td><td>Tool ← Rectangle</td><td>Tool ← Rectangle outline</td><td>redo</td></tr>
<tr><td><kbd>S</kbd></td><td>Tool ← Segment</td></tr>
<tr><td><kbd>U</kbd></td><td>undo</td></tr>
<tr><td><kbd>V</kbd></td><td>Mode ← Select</td></tr>
M website/index.xd => website/index.xd +6 -4
@@ 62,8 62,10 @@
[description-list
; [link-image Brush icon; assets/icons/tools/brush.png] Brush; The brush tool selects pixels that it moves over.
; [link-image Segment icon; assets/icons/tools/segment.png] Segment; The segment tool selects a line segment.
- ; [link-image Rectangle icon; assets/icons/tools/rectangle.png] Rectangle; The rectangle tool selects an axis-aligned rectangle.
- ; [link-image Ellipse icon; assets/icons/tools/ellipse.png] Ellipse; The ellipse tool selects the outline of an axis-aligned ellipse.
+ ; [link-image Rectangle icon; assets/icons/tools/rectangle-filled.png] Rectangle; The rectangle tool selects an axis-aligned rectangle.
+ ; [link-image Rectangle outline icon; assets/icons/tools/rectangle-outline.png] Rectangle outline; The rectangle tool selects the outline of an axis-aligned rectangle.
+ ; [link-image Ellipse icon; assets/icons/tools/ellipse-filled.png] Ellipse; The ellipse tool selects an axis-aligned ellipse.
+ ; [link-image Ellipse outline icon; assets/icons/tools/ellipse-outline.png] Ellipse outline; The ellipse outline tool selects the outline of an axis-aligned ellipse.
; [link-image Flood icon; assets/icons/tools/flood.png] Flood; The flood tool selects a contiguous area of pixels with the same color.
]
]
@@ 76,7 78,7 @@
[row [<kbd> B]; Tool ← Brush]
[row [<kbd> C]; Mode ← Color]
[row [<kbd> D]; delete pixel]
- [row [<kbd> E]; Tool ← Ellipse]
+ [row [<kbd> E]; Tool ← Ellipse; Tool ← Ellipse outline]
[row [<kbd> F]; Tool ← Flood]
[row [<kbd> H]; move left; [# move to left edge]; previous picture/palette]
[row [<kbd> I]; Mode ← Inject]
@@ 86,7 88,7 @@
[# row [<kbd> M]; Tool ← Mirror]
[row [<kbd> P]; paste]
[row [<kbd> Q]; quit; force quit]
- [row [<kbd> R]; Tool ← Rectangle; ; redo]
+ [row [<kbd> R]; Tool ← Rectangle; Tool ← Rectangle outline; redo]
[row [<kbd> S]; Tool ← Segment]
[row [<kbd> U]; undo]
[row [<kbd> V]; Mode ← Select]
R assets/icons/modes/add.png.license => website/screenshot.png.license +0 -0