Apply/revert buttons for overrides, container instances and child positions
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0b78382bcc
commit
3379232e64
7 files changed
+544
-37
No files matched your search
@@ -1,5 +1,12 @@
|
||||
import type { Container } from 'pixi.js';
|
||||
import { RenameAssetCommand, ResetAssetPropertyCommand, SetAssetPropertyCommand } from '../../core/commands/assetCommands';
|
||||
import {
|
||||
ApplyOverrideToAssetCommand,
|
||||
ApplyOverrideToContainerCommand,
|
||||
ApplyPositionToContainerCommand,
|
||||
RevertOverrideToTemplateCommand,
|
||||
RevertPositionToTemplateCommand,
|
||||
} from '../../core/commands/applyCommands';
|
||||
import { AddColliderCommand } from '../../core/commands/colliderCommands';
|
||||
import { RemoveNodeCommand, SetNodeParamCommand } from '../../core/commands/graphCommands';
|
||||
import {
|
||||
@@ -13,6 +20,7 @@ import { AddVariableCommand, nextVariableName, RemoveVariableCommand, RenameVari
|
||||
import { edgesInto, inlineInputDef, inlineInputs, nodeDef } from '../../core/graph';
|
||||
import type { Asset, BehaviorAsset, SceneAsset } from '../../core/model/Asset';
|
||||
import { isPlaceableType } from '../../core/model/AssetTypes';
|
||||
import { type TemplateLink, templateLinkOf } from '../../core/model/container';
|
||||
import { isSelfOrAncestor, treeOrder } from '../../core/model/hierarchy';
|
||||
import type { Position, PropertyValue } from '../../core/model/Properties';
|
||||
import { findAsset, findScene, findSceneObject } from '../../core/model/Project';
|
||||
@@ -101,7 +109,7 @@ export class Inspector extends Panel {
|
||||
if (s.objectIds.length > 1) return `multi|${s.objectIds.join(',')}`;
|
||||
const object = this.currentObject(s.sceneId, s.objectId);
|
||||
const asset = object && findAsset(this.state.project, object.assetId);
|
||||
return asset ? `${object.parentId}|` + schemaForAsset(asset).map((d) => `${d.key}:${d.kind}`).join(',') : 'missing';
|
||||
return asset ? `${object.parentId}|${object.templateId}|` + schemaForAsset(asset).map((d) => `${d.key}:${d.kind}`).join(',') : 'missing';
|
||||
}
|
||||
const asset = findAsset(this.state.project, s.assetId);
|
||||
if (!asset || asset.type !== 'behavior') return 'missing';
|
||||
@@ -250,29 +258,46 @@ export class Inspector extends Panel {
|
||||
|
||||
this.body.add(this.parentRow(scene, object, sceneId));
|
||||
|
||||
// Part of a placed container: values compare against the template, not just the asset.
|
||||
const link = templateLinkOf(this.state.project, scene, object);
|
||||
if (link) {
|
||||
const linkRow = new HStack({ gap: Theme.gap, align: 'center' });
|
||||
const linkLabel = new Label('Part of', { style: 'muted' });
|
||||
linkLabel.minWidth = FIELD_LABEL_WIDTH;
|
||||
linkRow.add(linkLabel);
|
||||
linkRow.add(new Button(link.asset.name, { variant: 'ghost', onClick: () => this.state.select({ kind: 'asset', assetId: link.asset.id }) }), 1);
|
||||
this.body.add(linkRow);
|
||||
}
|
||||
|
||||
// Position – belongs to the scene object only, local to the parent. Z is the draw order (higher = on top).
|
||||
const parent = object.parentId ? findSceneObject(scene, object.parentId) : undefined;
|
||||
this.body.add(new Label(parent ? 'POSITION (LOCAL TO PARENT)' : 'POSITION', { style: 'title' }));
|
||||
for (const axis of ['x', 'y', 'z'] as const) {
|
||||
let original: Position | undefined;
|
||||
const row = createFieldRow({ key: axis, label: axis.toUpperCase(), kind: 'number', default: 0, step: 1 }, object.position[axis], {
|
||||
onInput: (value) => {
|
||||
const target = this.currentObject(sceneId, objectId);
|
||||
if (!target) return;
|
||||
if (!original) original = { ...target.position };
|
||||
target.position[axis] = Number(value);
|
||||
this.state.preview();
|
||||
const row = createFieldRow(
|
||||
{ key: axis, label: axis.toUpperCase(), kind: 'number', default: 0, step: 1 },
|
||||
object.position[axis],
|
||||
{
|
||||
onInput: (value) => {
|
||||
const target = this.currentObject(sceneId, objectId);
|
||||
if (!target) return;
|
||||
if (!original) original = { ...target.position };
|
||||
target.position[axis] = Number(value);
|
||||
this.state.preview();
|
||||
},
|
||||
onChange: (value) => {
|
||||
const target = this.currentObject(sceneId, objectId);
|
||||
if (!target) return;
|
||||
const previous = original ?? { ...target.position };
|
||||
if (original) target.position = { ...original };
|
||||
original = undefined;
|
||||
const next = { ...previous, [axis]: Number(value) };
|
||||
this.state.execute(new MoveSceneObjectCommand(sceneId, objectId, next, previous));
|
||||
},
|
||||
},
|
||||
onChange: (value) => {
|
||||
const target = this.currentObject(sceneId, objectId);
|
||||
if (!target) return;
|
||||
const previous = original ?? { ...target.position };
|
||||
if (original) target.position = { ...original };
|
||||
original = undefined;
|
||||
const next = { ...previous, [axis]: Number(value) };
|
||||
this.state.execute(new MoveSceneObjectCommand(sceneId, objectId, next, previous));
|
||||
},
|
||||
});
|
||||
link ? () => this.state.execute(new RevertPositionToTemplateCommand(sceneId, objectId, axis)) : undefined,
|
||||
link ? [{ label: 'Apply to container', onSelect: () => this.state.execute(new ApplyPositionToContainerCommand(sceneId, objectId, axis)) }] : undefined,
|
||||
);
|
||||
this.fields.set(axis, row);
|
||||
this.body.add(row.row);
|
||||
}
|
||||
@@ -310,12 +335,16 @@ export class Inspector extends Panel {
|
||||
this.state.execute(new SetOverrideCommand(sceneId, objectId, def.key, value));
|
||||
},
|
||||
},
|
||||
() => this.state.execute(new ClearOverrideCommand(sceneId, objectId, def.key)),
|
||||
() => this.state.execute(link ? new RevertOverrideToTemplateCommand(sceneId, objectId, def.key) : new ClearOverrideCommand(sceneId, objectId, def.key)),
|
||||
[
|
||||
...(link ? [{ label: 'Apply to container', onSelect: () => this.state.execute(new ApplyOverrideToContainerCommand(sceneId, objectId, def.key)) }] : []),
|
||||
{ label: 'Apply to asset', onSelect: () => this.state.execute(new ApplyOverrideToAssetCommand(sceneId, objectId, def.key)) },
|
||||
],
|
||||
);
|
||||
row.setModified(isOverridden(object, def.key));
|
||||
this.fields.set(def.key, row);
|
||||
this.body.add(row.row);
|
||||
}
|
||||
this.markObjectRows(object, asset, link);
|
||||
|
||||
if (asset.type === 'container') {
|
||||
const count = asset.objects.length;
|
||||
@@ -474,18 +503,28 @@ export class Inspector extends Panel {
|
||||
}
|
||||
return;
|
||||
}
|
||||
const scene = findScene(this.state.project, s.sceneId);
|
||||
const object = this.currentObject(s.sceneId, s.objectId);
|
||||
const asset = object && findAsset(this.state.project, object.assetId);
|
||||
if (!object || !asset) return this.rebuild();
|
||||
if (!scene || !object || !asset) return this.rebuild();
|
||||
this.nameField?.setValue(object.name);
|
||||
this.fields.get('x')?.setValue(object.position.x);
|
||||
this.fields.get('y')?.setValue(object.position.y);
|
||||
this.fields.get('z')?.setValue(object.position.z);
|
||||
const values = resolveSceneObjectProps(asset, object);
|
||||
for (const def of schemaForAsset(asset)) this.fields.get(def.key)?.setValue(values[def.key] ?? def.default);
|
||||
this.markObjectRows(object, asset, templateLinkOf(this.state.project, scene, object));
|
||||
}
|
||||
|
||||
/**
|
||||
* Which rows deviate from their base: for a container instance the base is the template
|
||||
* (position and overrides), for any other object only overrides count as a deviation.
|
||||
*/
|
||||
private markObjectRows(object: SceneObject, asset: Asset, link: TemplateLink | undefined): void {
|
||||
for (const axis of ['x', 'y', 'z'] as const) this.fields.get(axis)?.setModified(Boolean(link) && object.position[axis] !== link!.template.position[axis]);
|
||||
for (const def of schemaForAsset(asset)) {
|
||||
const row = this.fields.get(def.key);
|
||||
row?.setValue(values[def.key] ?? def.default);
|
||||
row?.setModified(isOverridden(object, def.key));
|
||||
const modified = link ? object.overrides[def.key] !== link.template.overrides[def.key] : isOverridden(object, def.key);
|
||||
this.fields.get(def.key)?.setModified(modified);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user