Trim needless comments and fix the picker width
Remove comments that only restate the code, keeping the section banners and the notes that carry a reason, a measured fact or an external contract. ButtonOptions.width claimed to be a fixed width but only set minWidth, so the Graph and Texture pickers grew with the name they showed. It is now what it promises, with a separate minWidth for the buttons that have two forms. Narrow buttons shrink their padding, otherwise a 24px icon button had 8px left for its glyph and truncate dropped it entirely. __gm.labelsDropped() guards that class: the overflow guard only saw text that was too wide, never a label truncated to nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f16801aef3
commit
4d84231b9f
115 files changed
+707
-1564
No files matched your search
@@ -43,7 +43,6 @@ const MIN_LABEL_SIZE = 28;
|
||||
const LABEL_INSET = 3;
|
||||
const LABEL_PAD = 2;
|
||||
|
||||
/** A drag of an existing frame: which one, from what, and by which handle. */
|
||||
interface FrameDrag {
|
||||
frameId: string;
|
||||
handle: FrameHandle;
|
||||
@@ -52,7 +51,7 @@ interface FrameDrag {
|
||||
moved: boolean;
|
||||
}
|
||||
|
||||
/** A new frame being spanned on empty space (image pixels; nothing is in the model yet). */
|
||||
/** A new frame being spanned, in image pixels; nothing is in the model yet. */
|
||||
interface NewFrame {
|
||||
start: Vec2;
|
||||
current: Vec2;
|
||||
@@ -60,15 +59,8 @@ interface NewFrame {
|
||||
}
|
||||
|
||||
/**
|
||||
* The Texture tab's canvas: one texture's picture with its frames drawn on top, where frames
|
||||
* are created by dragging on empty space and moved or resized by their handles.
|
||||
*
|
||||
* Everything but the picture is drawn in widget-local pixels rather than in a zoomed
|
||||
* container: outlines, handles and names have to keep a constant size on screen, which a
|
||||
* scaled container would defeat. The picture itself is a Sprite whose scale is the zoom, so
|
||||
* the GPU does the sampling – and `scaleMode` follows the texture's own Filter property, so a
|
||||
* pixel-art sheet is inspected as crisp pixels rather than as the mush a smoothed preview
|
||||
* would show.
|
||||
* The Texture tab's canvas. Everything but the picture is drawn in widget-local pixels rather
|
||||
* than in a zoomed container: outlines, handles and names must keep a constant size on screen.
|
||||
*/
|
||||
export class TextureCanvas extends Widget {
|
||||
private readonly bg = new Graphics();
|
||||
@@ -127,7 +119,7 @@ export class TextureCanvas extends Widget {
|
||||
return { w: Math.max(this.minWidth, 200), h: Math.max(this.minHeight, 200) };
|
||||
}
|
||||
|
||||
/** Which texture is shown. Switching resets the view, since the next picture is a new subject. */
|
||||
/** Switching resets the view, since the next picture is a new subject. */
|
||||
show(assetId: string): void {
|
||||
if (this.assetId === assetId) return;
|
||||
this.assetId = assetId;
|
||||
@@ -139,17 +131,12 @@ export class TextureCanvas extends Widget {
|
||||
return this.assetId;
|
||||
}
|
||||
|
||||
/** Refits the picture into the widget – the "reset view" the toolbar offers. */
|
||||
fit(): void {
|
||||
this.needsFit = true;
|
||||
this.redraw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Where an image pixel currently sits on screen. Only the check scripts need this: dragging
|
||||
* a frame is done in image coordinates, so a test that cannot convert them can drag
|
||||
* somewhere but cannot aim at a known part of the picture.
|
||||
*/
|
||||
/** Where an image pixel sits on screen; only the check scripts need it, to aim drags. */
|
||||
imageToScreen(x: number, y: number): Vec2 {
|
||||
const local = imageToLocal(this.view, x, y);
|
||||
const origin = this.getGlobalPosition();
|
||||
@@ -176,9 +163,8 @@ export class TextureCanvas extends Widget {
|
||||
|
||||
private onPointerDown(e: FederatedPointerEvent): void {
|
||||
const asset = this.asset();
|
||||
// Nothing is cut from a picture whose size is unknown: `normalizeFrameRect` has no bounds
|
||||
// to hold such a frame inside, so it would keep a rectangle that lies off the sheet for
|
||||
// good. An unmeasured texture is a failed upload, and the hint says so.
|
||||
// Without a known picture size `normalizeFrameRect` has no bounds, and would keep a frame
|
||||
// that lies off the sheet.
|
||||
if (!asset || asset.width <= 0 || asset.height <= 0) return;
|
||||
const local = this.toLocal(e.global);
|
||||
if (e.button === 1 || (e.button === 0 && e.shiftKey)) {
|
||||
@@ -191,8 +177,7 @@ export class TextureCanvas extends Widget {
|
||||
const point = localToImage(this.view, local.x, local.y);
|
||||
const tolerance = HANDLE_SIZE / this.view.zoom;
|
||||
|
||||
// The selected frame is tested first and by its handles: it is the one being worked on,
|
||||
// and its handles must stay reachable even where a frame drawn later overlaps them.
|
||||
// The selected frame is tested first, so its handles stay reachable under a frame drawn later.
|
||||
const selected = this.frame(this.selectedFrameId());
|
||||
const onSelected = selected ? handleAt(selected, point, tolerance) : null;
|
||||
if (selected && onSelected) {
|
||||
@@ -309,7 +294,6 @@ export class TextureCanvas extends Widget {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
/** Announces what a press would do before it happens (resize arrows, move, crosshair). */
|
||||
private updateCursor(local: Vec2): void {
|
||||
const asset = this.asset();
|
||||
if (!asset) {
|
||||
@@ -345,7 +329,6 @@ export class TextureCanvas extends Widget {
|
||||
if (asset && texture) {
|
||||
this.image.texture = texture;
|
||||
this.image.position.set(this.view.panX, this.view.panY);
|
||||
// The sprite is drawn at the picture's own pixel size, so the zoom is the whole scale.
|
||||
this.image.width = asset.width * this.view.zoom;
|
||||
this.image.height = asset.height * this.view.zoom;
|
||||
}
|
||||
@@ -365,11 +348,7 @@ export class TextureCanvas extends Widget {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The checkerboard behind the picture. It is clipped to the picture rather than filling the
|
||||
* widget: its job is to make transparent pixels of *this image* visible, and a board that
|
||||
* ran past the edges would hide where the image actually ends.
|
||||
*/
|
||||
/** Clipped to the picture rather than filling the widget, which would hide where it ends. */
|
||||
private drawChecker(asset: TextureAsset | null, hasPicture: boolean): void {
|
||||
this.checker.clear();
|
||||
if (!asset || !hasPicture || asset.width <= 0) return;
|
||||
@@ -377,8 +356,8 @@ export class TextureCanvas extends Widget {
|
||||
const w = asset.width * this.view.zoom;
|
||||
const h = asset.height * this.view.zoom;
|
||||
this.checker.rect(origin.x, origin.y, w, h).fill(CHECKER_DARK);
|
||||
// Only the squares that land inside the widget are worth emitting; a 4000 px sheet at a
|
||||
// high zoom would otherwise cost tens of thousands of rectangles per redraw.
|
||||
// Only the squares inside the widget: a 4000 px sheet zoomed in would otherwise cost tens of
|
||||
// thousands of rectangles per redraw.
|
||||
const from = (start: number, limit: number) => Math.max(0, Math.floor((limit - start) / CHECKER_SIZE));
|
||||
const x0 = from(origin.x, 0);
|
||||
const y0 = from(origin.y, 0);
|
||||
@@ -467,15 +446,8 @@ export class TextureCanvas extends Widget {
|
||||
const x = at.x + LABEL_INSET;
|
||||
const y = at.y + LABEL_INSET;
|
||||
label.position.set(x + LABEL_PAD, y + LABEL_PAD);
|
||||
/*
|
||||
* A dark plate behind the name, not just a colour choice for the text.
|
||||
*
|
||||
* The name is drawn *on the user's picture*, which may be any colour – the grey used at
|
||||
* first vanished on the light quadrants of a test sheet, and no fixed colour can be safe on
|
||||
* an arbitrary image. The plate makes the background known, so light text on it always
|
||||
* reads. Same reasoning as the scene grid, which is drawn white at a low alpha rather than
|
||||
* in a theme colour so that it survives whatever the scene puts behind it.
|
||||
*/
|
||||
// A dark plate, not just a text colour: the name is drawn on the user's picture, where no
|
||||
// fixed colour is legible against every background.
|
||||
this.overlay
|
||||
.roundRect(x, y, label.width + LABEL_PAD * 2, label.height + LABEL_PAD * 2, 2)
|
||||
.fill({ color: 0x000000, alpha: selected ? 0.75 : 0.55 });
|
||||
|
||||
Reference in new issue
Block a user