The tab headers are one TabHeader, the node board and the tile board pan and zoom through one helper, reordering tile pictures and tilemap layers goes through one moveItem, and a tilemap cell is one named type (#85)
game-maker / gate (push) Successful in 1m42s
game-maker / suite (push) Successful in 6m9s

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5 committed 2026-09-18 16:01:12 +02:00
1 parent c91c18f495
commit 6d7d0005cf
19 files changed
+187 -195

No files matched your search

+13 -32
View File
@@ -1,9 +1,10 @@
import { Container, type FederatedPointerEvent, type FederatedWheelEvent, Graphics } from 'pixi.js';
import { Container, Graphics } from 'pixi.js';
import type { NodeDef } from '../../core/graph';
import { Button, HStack, Label, type Size, Spacer, Theme, VStack, Widget, zoomFactor } from '../../ui';
import { Button, Label, type Size, Spacer, Theme, VStack, Widget } from '../../ui';
import { type Box, frameBoxes } from '../framing';
import { drawGraphGrid, FIT_MARGIN, type GraphView, ZOOM_LIMITS, zoomedAbout } from '../graph/graphView';
import { drawGraphGrid, FIT_MARGIN, type GraphView, panAndZoom, ZOOM_LIMITS } from '../graph/graphView';
import { NodeView } from '../graph/NodeView';
import { TabHeader } from '../TabHeader';
/** One node as a plugin hands it over: a title at a position in graph units. */
export interface BoardNode {
@@ -50,7 +51,6 @@ class BoardCanvas extends Widget {
private readonly layer = new Container();
private readonly views: NodeView[] = [];
private view: GraphView = { pan: { x: 0, y: 0 }, zoom: 1 };
private panning: { start: { x: number; y: number }; pan: { x: number; y: number } } | null = null;
/** Framed once there is a size and something to frame; after that the view is the user's. */
private needsFit = true;
@@ -59,22 +59,14 @@ class BoardCanvas extends Widget {
this.layer.eventMode = 'none';
this.addChild(this.bg, this.grid, this.layer, this.clip);
this.layer.mask = this.clip;
this.on('pointerdown', (e: FederatedPointerEvent) => {
this.panning = { start: { x: e.global.x, y: e.global.y }, pan: { ...this.view.pan } };
});
this.on('globalpointermove', (e: FederatedPointerEvent) => {
if (!this.panning) return;
const { start, pan } = this.panning;
this.view.pan = { x: pan.x + e.global.x - start.x, y: pan.y + e.global.y - start.y };
this.applyView();
});
this.on('pointerup', () => (this.panning = null));
this.on('pointerupoutside', () => (this.panning = null));
this.on('wheel', (e: FederatedWheelEvent) => {
this.view = zoomedAbout(this.view, this.toLocal(e.global), zoomFactor(e.deltaY));
this.applyView();
e.preventDefault();
});
panAndZoom(
this,
() => this.view,
(view) => {
this.view = view;
this.applyView();
},
);
}
setNodes(nodes: readonly BoardNode[]): void {
@@ -138,14 +130,11 @@ export class NodeBoard extends VStack {
readonly fitButton: Button;
private readonly canvas = new BoardCanvas();
private readonly count = new Label('', { style: 'small', align: 'right' });
private readonly headerBg = new Graphics();
constructor() {
super();
this.fitButton = new Button('Fit', { onClick: () => this.fit() });
const header = new HStack({ gap: Theme.gap, padding: Theme.padding, align: 'center' });
header.minHeight = Theme.controlHeight + Theme.padding * 2;
header.addChildAt(this.headerBg, 0);
const header = new TabHeader();
header.add(this.fitButton);
header.add(new Spacer(), 1);
header.add(this.count);
@@ -169,12 +158,4 @@ export class NodeBoard extends VStack {
debugInfo(): ReturnType<BoardCanvas['debugInfo']> {
return this.canvas.debugInfo();
}
override redraw(): void {
super.redraw();
const h = Theme.controlHeight + Theme.padding * 2;
this.headerBg.clear();
this.headerBg.rect(0, 0, this.w, h).fill(Theme.colors.panelHeader);
this.headerBg.rect(0, h - 1, this.w, 1).fill(Theme.colors.border);
}
}
+2 -13
View File
@@ -1,5 +1,5 @@
import { Graphics } from 'pixi.js';
import { Checkbox, HStack, Label, ScrollContainer, Spacer, Theme, VStack } from '../../ui';
import { TabHeader } from '../TabHeader';
import type { PluginManager, PluginRecord } from './loader';
const NAME_WIDTH = 200;
@@ -65,7 +65,6 @@ class PluginRow extends HStack {
* reading a name out of it would mean running it.
*/
export class PluginsPane extends VStack {
private readonly headerBg = new Graphics();
private readonly hint: Label;
private readonly rows = new VStack();
private readonly scroll = new ScrollContainer();
@@ -75,9 +74,7 @@ export class PluginsPane extends VStack {
constructor() {
super();
const header = new HStack({ gap: Theme.gap, padding: Theme.padding, align: 'center' });
header.minHeight = Theme.controlHeight + Theme.padding * 2;
header.addChildAt(this.headerBg, 0);
const header = new TabHeader();
header.add(new Label('Plugins', { style: 'bodyBold' }));
header.add(new Spacer(Theme.padding));
this.hint = new Label('', { style: 'small' });
@@ -154,12 +151,4 @@ export class PluginsPane extends VStack {
this.scroll.relayoutContent();
this.relayout();
}
override redraw(): void {
super.redraw();
const h = Theme.controlHeight + Theme.padding * 2;
this.headerBg.clear();
this.headerBg.rect(0, 0, this.w, h).fill(Theme.colors.panelHeader);
this.headerBg.rect(0, h - 1, this.w, 1).fill(Theme.colors.border);
}
}