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:
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user