From 322e36c0f3c32268a2a996fcb44bb4deef332996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Sat, 7 Nov 2026 19:09:39 +0100 Subject: [PATCH] toolbar block icons centred in their 16px box (test for all icons), tutorials say where the objects tab is --- CHANGELOG.md | 3 ++ docs/manual/tutorial-first-level.md | 5 ++- docs/manual/tutorial-original-level.md | 3 +- docs/manual/tutorial-parkour.md | 3 +- .../editor/tools/geometry/GeoIcons.java | 9 +++-- .../llamamod/editor/ui/Icons.java | 5 +++ .../editor/tools/geometry/IconBoundsTest.java | 40 +++++++++++++++++++ 7 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 src/test/java/com/eliasmueller/llamamod/editor/tools/geometry/IconBoundsTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c084f4..b24a256 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ - **Editor:** flying with the right mouse button + W A S D / Q E now works even when another part of the window (a text field, a dock) still had the keyboard focus. +- **Editor:** the block, pillar and invisible-box icons sat too low in the toolbars (drawn outside + their box); a test now keeps every icon inside its 16 × 16 box. +- **Tutorials** say where the Objects panel is (the ⊙ tab next to *Outliner*). ## 0.2.2 – 2026-11-07 diff --git a/docs/manual/tutorial-first-level.md b/docs/manual/tutorial-first-level.md index 5efb7b9..4352990 100644 --- a/docs/manual/tutorial-first-level.md +++ b/docs/manual/tutorial-first-level.md @@ -40,8 +40,9 @@ Every change can be undone with **Ctrl+Z**. ## Step 4: A coin trail -1. Open the **Objects** panel (left) and click **Coin line** under the quick setups – or press - **O** for the **Coin line / arc** tool. +1. Open the **Objects** tab in the left dock – the ⊙ icon right next to *Outliner* (inactive tabs show only + their icon) and click **Coin line** under **Quick setups** – or press **O** for the + **Coin line / arc** tool. 2. Click once at the start of the trail and once at its end. Coins appear every *spacing* cells on the ground (also up the ramp). diff --git a/docs/manual/tutorial-original-level.md b/docs/manual/tutorial-original-level.md index f4cb18b..c024573 100644 --- a/docs/manual/tutorial-original-level.md +++ b/docs/manual/tutorial-original-level.md @@ -32,7 +32,8 @@ Every drag is one undo step – **Ctrl+Z** takes it back. ## Step 3: Add a checkpoint -1. Open the **Objects** panel (left dock) and click the quick setup **Checkpoint**. +1. Open the **Objects** tab in the left dock – the ⊙ icon right next to *Outliner* (inactive tabs show only + their icon) and click the quick setup **Checkpoint**. 2. The Place tool (**P**) is now active. Click on the ground where the checkpoint should stand. The editor places a checkpoint post together with its respawn point a little in front of it. diff --git a/docs/manual/tutorial-parkour.md b/docs/manual/tutorial-parkour.md index 97d0381..c3a9ee3 100644 --- a/docs/manual/tutorial-parkour.md +++ b/docs/manual/tutorial-parkour.md @@ -69,7 +69,8 @@ plane shows as material 30. Look for: The llama should not have to start over after every fall. -1. Open the **Objects** panel (left dock) and click **Checkpoint** in **Quick setups**. +1. Open the **Objects** tab in the left dock – the ⊙ icon right next to *Outliner* (inactive tabs show only + their icon) and click **Checkpoint** in **Quick setups**. 2. Click on a platform in the middle of the course. You get a checkpoint post with its respawn point just in front of it. Falling after passing it diff --git a/src/main/java/com/eliasmueller/llamamod/editor/tools/geometry/GeoIcons.java b/src/main/java/com/eliasmueller/llamamod/editor/tools/geometry/GeoIcons.java index befb3cd..d0f222c 100644 --- a/src/main/java/com/eliasmueller/llamamod/editor/tools/geometry/GeoIcons.java +++ b/src/main/java/com/eliasmueller/llamamod/editor/tools/geometry/GeoIcons.java @@ -19,8 +19,8 @@ final class GeoIcons { private static final Color RED = new Color(0xD93F3F); static void register() { - Icons.register("prim-box", (g, fg) -> block(g, 2, 5, 12, 8, TOP, SIDE)); - Icons.register("prim-platform", (g, fg) -> block(g, 1, 4, 14, 4, TOP, SIDE)); + Icons.register("prim-box", (g, fg) -> block(g, 2, 1, 12, 8, TOP, SIDE)); + Icons.register("prim-platform", (g, fg) -> block(g, 1, 2.5, 14, 4, TOP, SIDE)); Icons.register("prim-floor", (g, fg) -> { Path2D p = poly(1, 10, 8, 6.5, 15, 10, 8, 13.5); g.setColor(TOP); @@ -47,7 +47,7 @@ final class GeoIcons { g.setColor(fg); g.draw(p); }); - Icons.register("prim-pillar", (g, fg) -> block(g, 5, 2, 6, 12, STONE, STONE.darker())); + Icons.register("prim-pillar", (g, fg) -> block(g, 5, 0.5, 6, 12, STONE, STONE.darker())); Icons.register("prim-cylinder", (g, fg) -> { g.setColor(STONE.darker()); g.fill(new java.awt.geom.Rectangle2D.Double(2, 6, 12, 5)); @@ -122,7 +122,7 @@ final class GeoIcons { Icons.register("prim-invbox", (g, fg) -> { g.setStroke( new BasicStroke(1.2f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1, new float[] {2, 1.5f}, 0)); - outlineBlock(g, 2, 5, 12, 8, new Color(255, 60, 60, 60), RED); + outlineBlock(g, 2, 1, 12, 8, new Color(255, 60, 60, 60), RED); }); Icons.register("geo-collision", (g, fg) -> { Path2D p = poly(1, 10, 8, 6.5, 15, 10, 8, 13.5); @@ -221,6 +221,7 @@ final class GeoIcons { } /** Isometric block: x, y of the top-left, width w, side height h. */ + /** An isometric block filling y .. y + w / 2 + h; keep that within the 16 × 16 icon box. */ private static void block(Graphics2D g, double x, double y, double w, double h, Color top, Color side) { Color fg = g.getColor(); double d = w / 4; diff --git a/src/main/java/com/eliasmueller/llamamod/editor/ui/Icons.java b/src/main/java/com/eliasmueller/llamamod/editor/ui/Icons.java index b8acd82..210ddd6 100644 --- a/src/main/java/com/eliasmueller/llamamod/editor/ui/Icons.java +++ b/src/main/java/com/eliasmueller/llamamod/editor/ui/Icons.java @@ -40,6 +40,11 @@ public final class Icons { private Icons() {} + /** Names of all registered icons (sorted). */ + public static java.util.List names() { + return PAINTERS.keySet().stream().sorted().toList(); + } + public static void register(String name, Painter p) { PAINTERS.put(name, p); CACHE.keySet().removeIf(k -> k.startsWith(name + "@")); diff --git a/src/test/java/com/eliasmueller/llamamod/editor/tools/geometry/IconBoundsTest.java b/src/test/java/com/eliasmueller/llamamod/editor/tools/geometry/IconBoundsTest.java new file mode 100644 index 0000000..6c6bb86 --- /dev/null +++ b/src/test/java/com/eliasmueller/llamamod/editor/tools/geometry/IconBoundsTest.java @@ -0,0 +1,40 @@ +package com.eliasmueller.llamamod.editor.tools.geometry; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.eliasmueller.llamamod.editor.ui.Icons; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +/** Every vector icon stays inside its 16 × 16 box, so toolbar icons line up. */ +class IconBoundsTest { + @Test + void iconsStayInsideTheirBox() { + GeoIcons.register(); + List outside = new ArrayList<>(); + for (String name : Icons.names()) { + BufferedImage img = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = img.createGraphics(); + Icons.get(name, 16).paintIcon(null, g, 8, 8); + g.dispose(); + int minY = 32, maxY = -1, minX = 32, maxX = -1; + for (int y = 0; y < 32; y++) { + for (int x = 0; x < 32; x++) { + if ((img.getRGB(x, y) >>> 24) > 40) { + minY = Math.min(minY, y); + maxY = Math.max(maxY, y); + minX = Math.min(minX, x); + maxX = Math.max(maxX, x); + } + } + } + if (maxY >= 0 && (minY < 7 || maxY > 24 || minX < 7 || maxX > 24)) { + outside.add(name + " x " + (minX - 8) + ".." + (maxX - 8) + " y " + (minY - 8) + ".." + (maxY - 8)); + } + } + assertTrue(outside.isEmpty(), "icons drawn outside their 16x16 box: " + outside); + } +}