diff --git a/README.md b/README.md index 92330035..0b4ed385 100644 --- a/README.md +++ b/README.md @@ -351,8 +351,8 @@ inspector below X/Y/Z, undoable, with ↺ back to 0. It belongs to the placed ob A **collider** is an asset (`shape` box/circle, `width`/`height` or `radius`) placed like any other object – typically as a child of the sprite it belongs to, so its position is the offset -from that *body* and it moves with it. Right-click an object in **Scene objects** (or press -**+ Add collider** in its inspector) to get one with one click: a box collider sized like the +from that *body* and it moves with it. Right-click an object in **Scene objects** → *Add +collider* to get one with one click: a box collider sized like the sprite, parented at its centre. Colliders can be reused across objects, overridden per instance and stacked (hitbox + hurtbox on one sprite; colliders of the same body never collide with each other). They are editor symbols: green outlines in edit mode, invisible in play mode. @@ -644,7 +644,7 @@ npm run check # typecheck + lint + format:check + tests, what CI would ru # code is lost (tail's is reported), so a red run reads as green npm run build # writes dist/ and regenerates index.html export GM_REMOTE=user@host # optional: run the browser elsewhere; see below -node tools/seed-e2e.mjs && node tools/e2e.mjs # 535 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 537 editor checks, screenshots in /tmp/gm-e2e-*.png GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 – a subset while working on one step ./e2e.sh start [GM_STEPS] # the same run detached, see below ./e2e.sh status # live progress, or the last run's result diff --git a/src/editor/inspector/nodeSection.ts b/src/editor/inspector/nodeSection.ts index 8ed9398e..395e722a 100644 --- a/src/editor/inspector/nodeSection.ts +++ b/src/editor/inspector/nodeSection.ts @@ -1,4 +1,3 @@ -import { RemoveNodeCommand } from '../../core/commands/graphCommands'; import { callProblem, declaresVariablePorts, @@ -13,9 +12,9 @@ import type { Asset } from '../../core/model/Asset'; import { behaviorLookup } from '../../core/model/behaviorPrograms'; import { findAssetOf, type Project } from '../../core/model/Project'; import type { PropertyDef } from '../../core/properties/PropertySchema'; -import { Button, Label } from '../../ui'; +import { Label } from '../../ui'; import { createFieldRow, type FieldHandlers } from './fieldFactory'; -import { addGap, addNote, addTitle, type InspectorHost } from './host'; +import { addNote, addTitle, type InspectorHost } from './host'; import { buildPortSection, buildVariablePortSection } from './portSection'; import { listOpener, previewingHandlers } from './previewHandlers'; import { currentNode, nodeParamValue } from './valueSpecs'; @@ -81,14 +80,6 @@ export function buildNodeSection(host: InspectorHost, assetId: string, nodeId: s host.fields.set(`input:${port.key}`, row); host.body.add(row.row); } - - addGap(host); - host.body.add( - new Button('Delete node', { - variant: 'danger', - onClick: () => host.state.execute(new RemoveNodeCommand(assetId, nodeId)), - }), - ); } /** Pushes the node's current params into the rows. False when the node is gone (rebuild). */ diff --git a/src/editor/inspector/objectSection.ts b/src/editor/inspector/objectSection.ts index ed82310d..66552990 100644 --- a/src/editor/inspector/objectSection.ts +++ b/src/editor/inspector/objectSection.ts @@ -38,7 +38,7 @@ import { resolveSceneObjectProps, } from '../../core/properties/resolve'; import { Button, TextField } from '../../ui'; -import { addCollider, canAddCollider, createContainer, removeObjects } from '../actions'; +import { createContainer, removeObjects } from '../actions'; import { aspectActions, sizeCommand } from './aspectAction'; import { defSignature } from './assetSection'; import { createFieldRow, type FieldRow, labelledRow, type RowActions } from './fieldFactory'; @@ -230,17 +230,6 @@ export function buildObjectSection(host: InspectorHost, holderId: string, object markObjectRows(host, object, asset, target); if (asset.type === 'container') contentSection(host, holderId, object, asset.objects.length); - - const stored = findObjectHolder(project, holderId); - if (stored && canAddCollider(project, stored, object)) { - addGap(host); - host.body.add( - new Button('+ Add collider', { - variant: 'ghost', - onClick: () => addCollider(host.state, holderId, objectId), - }), - ); - } } /** diff --git a/todo-notes/done/inspector-buttons-entfernen.md b/todo-notes/done/inspector-buttons-entfernen.md new file mode 100644 index 00000000..6ef94310 --- /dev/null +++ b/todo-notes/done/inspector-buttons-entfernen.md @@ -0,0 +1,7 @@ +- Scene: Add collider button aus insepctor entfernen +- Graph: Delete node button aus inspector entfernen + +Umgesetzt: beide Aktionen bleiben erreichbar, nur nicht mehr im Inspector. +- Collider: Rechtsklick auf das Objekt in **Scene objects** → *Add collider*. Das ist jetzt der + einzige Weg; seine Sperre (Template-Inhalt, platzierter Container) prüft e2e 09 über das Menü. +- Node: `Delete` oder Rechtsklick auf den Node → *Delete node*. diff --git a/todo-notes/inspector-buttons-entfernen.md b/todo-notes/inspector-buttons-entfernen.md deleted file mode 100644 index 3813c40b..00000000 --- a/todo-notes/inspector-buttons-entfernen.md +++ /dev/null @@ -1,2 +0,0 @@ -- Scene: Add collider button aus insepctor entfernen -- Graph: Delete node button aus inspector entfernen diff --git a/tools/e2e/06-graph.mjs b/tools/e2e/06-graph.mjs index 8a54bfab..87899a31 100644 --- a/tools/e2e/06-graph.mjs +++ b/tools/e2e/06-graph.mjs @@ -233,6 +233,8 @@ export async function graph(t) { // 13e. Delete removes the selected node together with its edge; undo brings both back. await select({ kind: 'node', assetId: 'mover', nodeId: newNode.id }); + await sleep(200); + check('the node inspector has no delete button of its own', !(await t.has('Delete node'))); await press('Delete'); await sleep(150); const deleted = await graphCounts(); diff --git a/tools/e2e/09-containers.mjs b/tools/e2e/09-containers.mjs index fe69e765..25e3ebda 100644 --- a/tools/e2e/09-containers.mjs +++ b/tools/e2e/09-containers.mjs @@ -296,12 +296,33 @@ export async function containers(t) { // 16i. Structure is the template's business: resolved content cannot be removed, re-parented, // given a collider or turned into a container of its own. - await selectObject(redA); - check('the inspector offers no collider for resolved content', !(await has('+ Add collider'))); - await selectObject(instanceA.id); + // The hierarchy menu is the only way to a collider, and a disabled entry must not even reach + // the command: the command refuses too, but with a notice. + const colliderFromMenu = async (id) => { + await selectObject(id); + const row = await json(`__gm.hierarchyRow(${JSON.stringify(id)})`); + const before = (await objects()).length; + const noticeNow = await notice(); + await click(row.x, row.y, 'right'); + await sleep(150); + await clickText('Add collider'); + await sleep(200); + await press('Escape'); + await sleep(100); + return { added: (await objects()).length - before, notice: await noticeNow() }; + }; + const refused = JSON.stringify({ added: 0, notice: '' }); + const fromContent = await colliderFromMenu(redA); check( - 'nor for the placed container itself, which the command refuses as the hierarchy menu does', - !(await has('+ Add collider')), + 'the menu offers no collider for resolved content', + JSON.stringify(fromContent) === refused, + JSON.stringify(fromContent), + ); + const fromInstance = await colliderFromMenu(instanceA.id); + check( + 'nor for the placed container itself', + JSON.stringify(fromInstance) === refused, + JSON.stringify(fromInstance), ); const plainId = await json(`(() => { const p = __gm.state.project; @@ -311,11 +332,15 @@ export async function containers(t) { return sprite ? sprite.id : null; })()`); await selectObject(plainId); + check('the inspector has no collider button of its own', !(await has('+ Add collider'))); + const fromPlain = await colliderFromMenu(plainId); check( - 'while a plain sprite still gets it', - Boolean(plainId) && (await has('+ Add collider')), - JSON.stringify({ plainId }), + 'while a plain sprite still gets one from the menu', + fromPlain.added === 1, + JSON.stringify(fromPlain), ); + await undo(); + await sleep(200); await selectObject(redA); let noticeAfter = await notice(); await press('Delete');