Add icons for eraser, select, and move tools

- Eraser: angled rectangle with dividing line (eraser tip)
- Select: dashed rectangle (marquee selection)
- Move: four-way arrow cross with arrowheads
All icons match the existing pen dot, line, and box icon style.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 17:02:36 -07:00
parent b902aaa721
commit e4f55738de

View File

@@ -111,6 +111,79 @@ private fun BoxIcon(selected: Boolean) {
} }
} }
/** Eraser icon — rectangle at an angle with a line underneath. */
@Composable
private fun EraserIcon(selected: Boolean) {
val color = if (selected) Color.White else Color.Black
Canvas(modifier = Modifier.size(18.dp)) {
val w = size.width
val h = size.height
val path = androidx.compose.ui.graphics.Path().apply {
// Angled eraser body
moveTo(w * 0.6f, h * 0.15f)
lineTo(w * 0.9f, h * 0.45f)
lineTo(w * 0.5f, h * 0.85f)
lineTo(w * 0.2f, h * 0.55f)
close()
}
drawPath(path, color = color, style = Stroke(width = 1.5f * density, cap = StrokeCap.Round))
// Dividing line between eraser tip and body
drawLine(color, Offset(w * 0.55f, h * 0.5f), Offset(w * 0.35f, h * 0.7f), 1.5f * density)
}
}
/** Select icon — dashed rectangle (marquee). */
@Composable
private fun SelectIcon(selected: Boolean) {
val color = if (selected) Color.White else Color.Black
Canvas(modifier = Modifier.size(18.dp)) {
val inset = 2f
drawRect(
color = color,
topLeft = Offset(inset, inset),
size = androidx.compose.ui.geometry.Size(size.width - inset * 2, size.height - inset * 2),
style = Stroke(
width = 1.5f * density,
pathEffect = androidx.compose.ui.graphics.PathEffect.dashPathEffect(
floatArrayOf(4f * density, 3f * density), 0f,
),
),
)
}
}
/** Move icon — four-way arrow (cross with arrowheads). */
@Composable
private fun MoveIcon(selected: Boolean) {
val color = if (selected) Color.White else Color.Black
Canvas(modifier = Modifier.size(18.dp)) {
val w = size.width
val h = size.height
val cx = w / 2f
val cy = h / 2f
val arm = w * 0.35f
val head = w * 0.12f
val sw = 1.5f * density
// Cross lines
drawLine(color, Offset(cx, cy - arm), Offset(cx, cy + arm), sw, StrokeCap.Round)
drawLine(color, Offset(cx - arm, cy), Offset(cx + arm, cy), sw, StrokeCap.Round)
// Up arrow
drawLine(color, Offset(cx, cy - arm), Offset(cx - head, cy - arm + head), sw, StrokeCap.Round)
drawLine(color, Offset(cx, cy - arm), Offset(cx + head, cy - arm + head), sw, StrokeCap.Round)
// Down arrow
drawLine(color, Offset(cx, cy + arm), Offset(cx - head, cy + arm - head), sw, StrokeCap.Round)
drawLine(color, Offset(cx, cy + arm), Offset(cx + head, cy + arm - head), sw, StrokeCap.Round)
// Left arrow
drawLine(color, Offset(cx - arm, cy), Offset(cx - arm + head, cy - head), sw, StrokeCap.Round)
drawLine(color, Offset(cx - arm, cy), Offset(cx - arm + head, cy + head), sw, StrokeCap.Round)
// Right arrow
drawLine(color, Offset(cx + arm, cy), Offset(cx + arm - head, cy - head), sw, StrokeCap.Round)
drawLine(color, Offset(cx + arm, cy), Offset(cx + arm - head, cy + head), sw, StrokeCap.Round)
}
}
/** Undo arrow icon (curved left arrow). */ /** Undo arrow icon (curved left arrow). */
@Composable @Composable
private fun UndoIcon(enabled: Boolean) { private fun UndoIcon(enabled: Boolean) {
@@ -319,9 +392,15 @@ fun EditorToolbar(
BoxIcon(currentTool == Tool.BOX) BoxIcon(currentTool == Tool.BOX)
} }
TextToolButton("Eraser", currentTool == Tool.ERASER, { onToolSelected(Tool.ERASER) }) ToolButton(selected = currentTool == Tool.ERASER, onClick = { onToolSelected(Tool.ERASER) }) {
TextToolButton("Select", currentTool == Tool.SELECT, { onToolSelected(Tool.SELECT) }) EraserIcon(currentTool == Tool.ERASER)
TextToolButton("Move", currentTool == Tool.MOVE, { onToolSelected(Tool.MOVE) }) }
ToolButton(selected = currentTool == Tool.SELECT, onClick = { onToolSelected(Tool.SELECT) }) {
SelectIcon(currentTool == Tool.SELECT)
}
ToolButton(selected = currentTool == Tool.MOVE, onClick = { onToolSelected(Tool.MOVE) }) {
MoveIcon(currentTool == Tool.MOVE)
}
// Selection operations // Selection operations
if (hasSelection || canPaste) { if (hasSelection || canPaste) {