Keep Fit inside the song tab's header again (#429)

Suite 719 for 0dd671e was red in e2e 65. The Arrange button that came
with b9d1602 sits in every graph tab's header, the song's too. There it
pushed Bake and Fit past the right edge of the tab. The Fit click hit
nothing, the last track stayed below the edge, and its head menu with
"Add track below" never opened.

- The song tab shows Arrange with its routing only. On the timeline it
  was greyed out and of no use anyway.
- SnapToggle.setArrangeShown hides the button and lays its header out
  again, so the timeline's header is as wide as before #429.
- The magnet stays where it was, greyed out on the timeline, as e2e 65
  expects.

The other red check in suite 719, e2e 34 "the pause holds the stream",
is the wobble left open in 5b9d084 (task 712). Its message now shows
the stream behind before the pause already (skipped 12950), so the
pause did not lose its place. On melektaus-atx it passed.

Tests:
- snap-toggle.test.ts 6/6, the new test is red without the relayout
- e2e 65 on melektaus-atx: red before (same error as in CI), now
  ALL PASSED, 59 checks
- Gate on melektaus-atx: CHECK EXIT 0, 318 files, 4931 tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-18 12:48:15 +02:00
1 parent 0dd671ea26
commit 732989a452
3 files changed
+30 -3

No files matched your search

+12 -1
View File
@@ -1,4 +1,4 @@
import { Button, Theme } from '../../ui';
import { Button, Stack, Theme } from '../../ui';
import { HEADER_ICON_SVG } from '../panels/headerIcons';
/** Whatever a tab snaps: the graph canvas, the vector art canvas. A graph arranges its nodes too. */
@@ -58,4 +58,15 @@ export class SnapToggle {
this.button.setEnabled(on);
this.arrangeButton?.setEnabled(on);
}
/**
* Shows or hides *Arrange*, for a tab whose graph is one of its views: the song's timeline has
* no use for it, and a header that wide pushed *Fit* past the edge of the tab.
*/
setArrangeShown(on: boolean): void {
const button = this.arrangeButton;
if (!button || button.visible === on) return;
button.visible = on;
if (button.parent instanceof Stack) button.parent.relayout();
}
}
+2 -1
View File
@@ -217,10 +217,11 @@ export class SongEditor extends AssetTabEditor<SongAsset, SongTimeline> {
this.syncPlayButton();
}
/** The grid is the timeline's, the snap the routing's. */
/** The grid is the timeline's, the snap the routing's, and *Arrange* only shows with the routing. */
private syncViewButtons(asset: SongAsset | null): void {
this.gridButton.setEnabled(asset !== null && this.shown === 'timeline');
this.snap.setEnabled(asset !== null && this.shown === 'routing');
this.snap.setArrangeShown(this.shown === 'routing');
}
protected override body(canvas: SongTimeline): Widget {
+16 -1
View File
@@ -5,7 +5,7 @@
import { beforeAll, describe, expect, it, vi } from 'vitest';
import { CanvasTextMetrics } from 'pixi.js';
import { GRAPH_SNAPS_AT_FIRST, SnapToggle } from '../../src/editor/graph/SnapToggle';
import { Theme } from '../../src/ui';
import { Button, HStack, Theme } from '../../src/ui';
// Node has no DOMParser to read the file with; what the magnet looks like is the icon tests' job.
vi.mock('../../src/ui/svg', () => ({ drawSvg: () => undefined, tintSvg: (svg: string) => svg }));
@@ -67,6 +67,21 @@ describe('SnapToggle', () => {
expect(new SnapToggle(() => canvas).arrangeButton).toBeNull();
});
it('hides Arrange from a header it shares, which then lays the rest out without it', () => {
const snap = new SnapToggle(() => target(), GRAPH_SNAPS_AT_FIRST, true);
const header = new HStack({ gap: 4 });
const fit = new Button('Fit');
for (const widget of [...snap.widgets, fit]) header.add(widget);
header.resize(400, Theme.controlHeight);
const shownAt = fit.x;
snap.setArrangeShown(false);
expect(snap.arrangeButton!.visible).toBe(false);
expect(fit.x).toBeLessThan(shownAt);
snap.setArrangeShown(true);
expect(fit.x).toBe(shownAt);
new SnapToggle(() => target()).setArrangeShown(false);
});
it('asks for the target at the click, so a canvas mounted later is the one switched', () => {
let canvas = target();
const snap = new SnapToggle(() => canvas);