A sprite's texture and shader were only reachable by hunting for them
in the asset panel. Every place that shows such a reference now leads
straight to it.
- Object menu (hierarchy and scene view): "Open texture" and "Open
shader" sit right below "Open asset" when the sprite has one. The
object's own values count, so an overridden shader opens the
override.
- Asset context menu: the same entries at the top.
- Inspector: every asset field with a value shows its label as a blue,
underlined link. One click selects the asset, a double click opens
it. An override stays gold and gets the underline too.
- The first click rebuilds the inspector, so the second one lands on a
different row. The inspector catches that second click before any
row sees it.
- New pure rule `references.ts`: the asset behind a reference field. A
frame leads to its sheet. Kinds without a tab (palette, font, sound)
get no menu entry.
- `followsPress` in `clicks.ts` keeps the double-click window and
tolerance in one place.
- `activateAsset` in `actions.ts`: opening means the same everywhere
as a double click in the asset panel, so a scene also becomes the
active one. The asset panel uses it too.
Tests:
- ./check.sh: 150 files, 2226 tests, CHECK EXIT 0 (before 148/2214).
- 12 new unit tests: 6 for the reference rule, 4 for the link in
createFieldRow, 2 for followsPress.
- 5 new e2e checks in 28l-ii: both menus, the link's look, click
selects, double click opens.
- e2e 1-16,26,28,35,39,40 on the final build: ALL PASSED, 732 checks.
- Counter-probes: no "Open ..." entries, no underline and a second
click never recognised each fail exactly at their checks.
- Check total 1341 (CI counted 1336 at fd6af84), computed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
38 lines
1.4 KiB
TypeScript
38 lines
1.4 KiB
TypeScript
import { type PropertyBag, type PropertyValue, textOf } from '../model/Properties';
|
||
import { findPixelFrame } from '../model/pixelart';
|
||
import { findAsset, type Project } from '../model/Project';
|
||
import { findFrame } from '../model/texture';
|
||
import { isKindWith } from './kinds';
|
||
import type { PropertyDef } from './PropertySchema';
|
||
|
||
/**
|
||
* The asset a reference field points at, null when it names nothing or no longer resolves. A frame
|
||
* names the texture or pixel art it was cut from – that is the asset one can open (#221).
|
||
*/
|
||
export function referencedAssetId(project: Project, def: PropertyDef, value: PropertyValue): string | null {
|
||
if (!isKindWith('reference', def.kind)) return null;
|
||
const id = textOf(value);
|
||
if (id === '') return null;
|
||
if (findAsset(project, id)) return id;
|
||
if (def.kind !== 'texture') return null;
|
||
return findFrame(project, id)?.asset.id ?? findPixelFrame(project, id)?.asset.id ?? null;
|
||
}
|
||
|
||
export interface Reference {
|
||
label: string;
|
||
assetId: string;
|
||
}
|
||
|
||
/** Every reference of a bag that resolves, in schema order – the "Open …" entries of a menu. */
|
||
export function referencesOf(
|
||
project: Project,
|
||
schema: readonly PropertyDef[],
|
||
values: PropertyBag,
|
||
): Reference[] {
|
||
return schema.flatMap((def) => {
|
||
const value = values[def.key];
|
||
const assetId = value === undefined ? null : referencedAssetId(project, def, value);
|
||
return assetId ? [{ label: def.label, assetId }] : [];
|
||
});
|
||
}
|