Add a decimals option, fix dropdown overflow and the texture filter

- NumberField takes a decimals option (default 3); frame rects and the
  slice dialog use 0, matching their integer model.
- Button truncates its label to the drawn width; Dropdown reserves the
  chevron slot. NodeView reuses the shared truncate().
- Setting scaleMode leaves the style's shared resource id in place, so
  the old GPU sampler stayed in use until a reload. Call style.update().
- Graph gets a header bar like the Texture tab: GraphEditor is now the
  frame, the former editor is GraphCanvas. A selection the tab does not
  concern no longer unloads the behavior.
- New e2e step 14 guards text overflow across all widgets.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5 committed 2026-09-08 15:05:28 +02:00
1 parent 35a1a23af8
commit f16801aef3
22 files changed
+874 -493

No files matched your search

+4 -14
View File
@@ -1,4 +1,4 @@
import { CanvasTextMetrics, Graphics, Rectangle, Text } from 'pixi.js';
import { Graphics, Rectangle, Text } from 'pixi.js';
import {
asString,
edgesInto,
@@ -17,7 +17,7 @@ import type { Project } from '../../core/model/Project';
import type { PropertyValue } from '../../core/model/Properties';
import { assetRefLabel } from '../../core/properties/assetRef';
import type { PropertyDef } from '../../core/properties/PropertySchema';
import { formatNumber, Theme, textStyle, type TextStyleToken, Widget } from '../../ui';
import { formatNumber, Theme, textStyle, type TextStyleToken, truncate, Widget } from '../../ui';
import { keyLabel } from '../inspector/fieldFactory';
/**
@@ -75,7 +75,7 @@ export interface PortHit {
/**
* Draws one graph node: a title bar coloured by category, a line per setting and a row per
* port pair (inputs left, outputs right). Everything is derived from the NodeDef; the view
* never interprets what a node does. Positioned in graph coordinates by the GraphEditor.
* never interprets what a node does. Positioned in graph coordinates by the GraphCanvas.
*/
export class NodeView extends Widget {
private readonly box = new Graphics();
@@ -166,7 +166,7 @@ export class NodeView extends Widget {
align: 'left' | 'right' = 'left',
maxWidth = NODE_WIDTH - PAD * 2,
) => {
const node = new Text({ text: fit(text, style, maxWidth), style: textStyle(style) });
const node = new Text({ text: truncate(text, textStyle(style), maxWidth), style: textStyle(style) });
node.position.set(align === 'left' ? x : x - node.width, y);
this.addChild(node);
this.texts.push(node);
@@ -270,13 +270,3 @@ function formatValue(value: Value): string {
if (typeof value === 'boolean') return value ? 'true' : 'false';
return asString(value);
}
/** Truncates with an ellipsis so the text fits `maxWidth`. */
function fit(text: string, style: TextStyleToken, maxWidth: number): string {
const s = textStyle(style);
if (CanvasTextMetrics.measureText(text, s).width <= maxWidth) return text;
let cut = text;
while (cut.length > 1 && CanvasTextMetrics.measureText(cut + '…', s).width > maxWidth)
cut = cut.slice(0, -1);
return cut + '…';
}