The active tilemap layer can be renamed from the painting section, and a Show setting fades or hides the other layers in the scene view while the tilemap is selected (#138)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bfbcbe604c
commit
f53279d065
10 files changed
+248
-13
No files matched your search
@@ -10,15 +10,23 @@ import {
|
||||
AddTilemapLayerCommand,
|
||||
MoveTilemapLayerCommand,
|
||||
RemoveTilemapLayerCommand,
|
||||
RenameTilemapLayerCommand,
|
||||
SetTilemapLayerHiddenCommand,
|
||||
} from '../../core/commands/tilemapCommands';
|
||||
import type { TilemapAsset } from '../../core/model/Asset';
|
||||
import { isLayerVisible } from '../../core/model/tilemap';
|
||||
import { Button, Checkbox, HStack, Theme } from '../../ui';
|
||||
import type { EditorState, TilemapTool } from '../state';
|
||||
import { findLayer, isLayerVisible } from '../../core/model/tilemap';
|
||||
import { Button, Checkbox, Dropdown, HStack, Menu, TextField, Theme } from '../../ui';
|
||||
import type { EditorState, TilemapFocus, TilemapTool } from '../state';
|
||||
import { TilePalette } from '../tile/TilePalette';
|
||||
import { labelledRow } from './fieldFactory';
|
||||
import { addGap, addNote, addTitle, type InspectorHost } from './host';
|
||||
|
||||
const FOCUS: { focus: TilemapFocus; label: string }[] = [
|
||||
{ focus: 'all', label: 'All layers' },
|
||||
{ focus: 'dim', label: 'Others faded' },
|
||||
{ focus: 'solo', label: 'Active layer only' },
|
||||
];
|
||||
|
||||
const TOOLS: { tool: TilemapTool; label: string; hint: string }[] = [
|
||||
{ tool: 'select', label: 'Select', hint: 'Drag the map to move it, as any other object.' },
|
||||
{ tool: 'brush', label: 'Brush', hint: 'Drag over the map to paint a line of cells.' },
|
||||
@@ -46,6 +54,10 @@ export interface TilemapSectionWidgets {
|
||||
/** Null while the project has no tile. */
|
||||
palette: TilePalette | null;
|
||||
layers: { id: string; name: Button; visible: Checkbox; up: Button; down: Button; remove: Button }[];
|
||||
/** The name of the layer painted on (#138). */
|
||||
layerName: TextField;
|
||||
/** How the other layers are shown in the scene view (#138). */
|
||||
focus: Dropdown;
|
||||
addLayer: Button;
|
||||
}
|
||||
|
||||
@@ -58,10 +70,31 @@ export function currentTilemapSection(): TilemapSectionWidgets | null {
|
||||
export function buildTilemapSection(host: InspectorHost, asset: TilemapAsset): void {
|
||||
const { state } = host;
|
||||
const paint = state.tilemapPaint;
|
||||
const painted = paintedLayerId(state, asset);
|
||||
const paintedName = findLayer(asset, painted)?.name ?? '';
|
||||
const layerName: TextField = new TextField(paintedName, {
|
||||
onChange: (name) => {
|
||||
// The command rejects a blank name but cannot put the old text back into the field,
|
||||
// so an empty one is not sent at all.
|
||||
if (name.trim()) state.execute(new RenameTilemapLayerCommand(asset.id, painted, name));
|
||||
else layerName.setValue(paintedName);
|
||||
},
|
||||
});
|
||||
const focus: Dropdown = new Dropdown(FOCUS.find((f) => f.focus === paint.focus)?.label ?? '', {
|
||||
onClick: () =>
|
||||
new Menu(
|
||||
FOCUS.map((f) => ({
|
||||
label: f.focus === paint.focus ? `● ${f.label}` : f.label,
|
||||
onSelect: () => state.setTilemapPaint({ focus: f.focus }),
|
||||
})),
|
||||
).openBelow(focus),
|
||||
});
|
||||
const widgets: TilemapSectionWidgets = {
|
||||
tools: new Map(),
|
||||
palette: null,
|
||||
layers: [],
|
||||
layerName,
|
||||
focus,
|
||||
addLayer: new Button('Add layer', {
|
||||
onClick: () => state.execute(new AddTilemapLayerCommand(asset.id)),
|
||||
}),
|
||||
@@ -98,7 +131,6 @@ export function buildTilemapSection(host: InspectorHost, asset: TilemapAsset): v
|
||||
|
||||
addTitle(host, 'LAYERS');
|
||||
addNote(host, 'The last layer is drawn on top.', 'small');
|
||||
const painted = paintedLayerId(state, asset);
|
||||
// Bottom-up on screen, as in every layer list: the topmost row is the one drawn last.
|
||||
for (let index = asset.layers.length - 1; index >= 0; index--) {
|
||||
const layer = asset.layers[index]!;
|
||||
@@ -134,6 +166,15 @@ export function buildTilemapSection(host: InspectorHost, asset: TilemapAsset): v
|
||||
widgets.layers.push({ id: layer.id, name: choose, visible, up, down, remove });
|
||||
host.body.add(row);
|
||||
}
|
||||
// Below the list rather than in it: a row is a button that picks the layer, and a text field
|
||||
// in its place would take the click that chooses it.
|
||||
const nameRow = labelledRow('Name').row;
|
||||
nameRow.add(layerName, 1);
|
||||
host.body.add(nameRow);
|
||||
const showRow = labelledRow('Show').row;
|
||||
showRow.add(focus, 1);
|
||||
host.body.add(showRow);
|
||||
addNote(host, 'Show only changes the scene view, not the game.', 'small');
|
||||
addGap(host);
|
||||
host.body.add(widgets.addLayer);
|
||||
}
|
||||
@@ -152,5 +193,5 @@ export function tilemapSignature(state: EditorState, asset: TilemapAsset): strin
|
||||
const paint = state.tilemapPaint;
|
||||
const layers = asset.layers.map((l) => `${l.id}:${l.name}:${isLayerVisible(l) ? 1 : 0}`).join(',');
|
||||
const tiles = tileIdsOf(state).join(',');
|
||||
return `${paint.tool}|${paint.tileId}|${paintedLayerId(state, asset)}|${layers}|${tiles}`;
|
||||
return `${paint.tool}|${paint.tileId}|${paintedLayerId(state, asset)}|${paint.focus}|${layers}|${tiles}`;
|
||||
}
|
||||
Reference in new issue
Block a user