Scroll the rows of the animation timeline up and down (#413)
An animation with more rows than the panel is tall cut the bottom rows off. There was no way to reach them, their fields or their keys. - The view has a new `scrollY`. Rows scroll up under the ruler, which stays where it is together with the tab head. - The wheel over the header column scrolls the rows. Over the cells it still zooms, and `Shift`+wheel still scrolls across. - A scrollbar at the right edge shows up only when the rows do not fit. Its thumb can be dragged, a click beside it jumps there. - The middle button pans both ways. `Shift`+drag stays across only. - A row picked or added out of view is scrolled just far enough to be seen whole. Value fields out of view are not drawn. - The tab keeps its scroll like its zoom when switching. Found on the way: `zoomCells` built a new view from `panX` and `cellWidth` only, so every zoom would have dropped the scroll. The type check caught it, and a unit test now holds it. Tests: - tsc, eslint, Prettier clean - Unit timeline-view: 20 green, 6 new. Bending `rowAt` to ignore the scroll or `revealRow` to do nothing turns exactly those tests red. - e2e 25 on melektaus-atx: ALL PASSED, 37 checks (25j, 25j-ii new). 32 rows, the wheel brings the last field into view and typing keys 77 there. Dragging the thumb up goes back to 0. - Gate on melektaus-atx: green, 305 files, 4730 tests. - Not checked in the browser: the middle button, revealing a picked row, the wheel right over a value field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0648853356
commit
480db9c4e4
6 files changed
+341
-56
No files matched your search
@@ -12,7 +12,7 @@ const SIZE = 40;
|
||||
* removes everything it made.
|
||||
*/
|
||||
export async function animation(t) {
|
||||
const { check, json, evaluate, mutate, shot, click, doubleClick, drag, press, typeText } = t;
|
||||
const { check, json, evaluate, mutate, shot, click, doubleClick, drag, press, typeText, wheel } = t;
|
||||
const { undo, settle, sleep, waitUntil, find } = t;
|
||||
|
||||
await press('Escape');
|
||||
@@ -496,6 +496,55 @@ export async function animation(t) {
|
||||
JSON.stringify({ shownX, keyedX }),
|
||||
);
|
||||
|
||||
// 25j. More rows than room (#413): 16 objects with a row each. The wheel over the header column
|
||||
// scrolls the rows, the last one comes into view and its field keys a typed value; the
|
||||
// scrollbar's thumb dragged up takes them back to the top.
|
||||
await mutate(`
|
||||
const p = __gm.state.project;
|
||||
const box = p.assets.find((a) => a.id === 'an-box');
|
||||
const arm = box.objects[0];
|
||||
for (let i = 2; i <= 16; i++)
|
||||
box.objects.push({ ...structuredClone(arm), id: 'an-arm' + i, name: 'Arm ' + i });
|
||||
p.assets.find((a) => a.id === 'an-walk').tracks = box.objects.map((o, i) => (
|
||||
{ id: i === 15 ? 'an-last' : 'an-s' + i, target: o.id, property: 'x', keys: [] }
|
||||
));
|
||||
`);
|
||||
await evaluate('__gm.animation.scrub(2)');
|
||||
await sleep(150);
|
||||
const before = { view: await json('__gm.animation.view()'), thumb: await json('__gm.animation.thumb()') };
|
||||
const lastHidden = await json("__gm.animation.valueAt('an-last')");
|
||||
const header = await json("__gm.animation.headerAt('an-s0')");
|
||||
await wheel(header.x, header.y, 5000);
|
||||
const scrolled = await json('__gm.animation.view()');
|
||||
const lastField = await json("__gm.animation.valueAt('an-last')");
|
||||
if (lastField) {
|
||||
await click(lastField.x, lastField.y);
|
||||
await typeText('77');
|
||||
await press('Enter');
|
||||
await sleep(150);
|
||||
}
|
||||
const lastKeys = (await walk()).tracks.find((r) => r.id === 'an-last').keys;
|
||||
check(
|
||||
'the wheel over the headers scrolls to the last row, and its field keys a typed value',
|
||||
before.view.scrollY === 0 &&
|
||||
before.thumb !== null &&
|
||||
lastHidden === null &&
|
||||
scrolled.scrollY === before.thumb.max &&
|
||||
scrolled.cellWidth === before.view.cellWidth &&
|
||||
lastField !== null &&
|
||||
JSON.stringify(lastKeys) === JSON.stringify([{ frame: 2, value: 77 }]),
|
||||
JSON.stringify({ before, lastHidden, scrolled, lastField, lastKeys }),
|
||||
);
|
||||
await shot('21-scrolled-rows');
|
||||
const thumb = await json('__gm.animation.thumb()');
|
||||
await drag(thumb.x, thumb.y, thumb.x, 5);
|
||||
const toTop = await json('__gm.animation.view()');
|
||||
check(
|
||||
'the scrollbar thumb dragged up takes the rows back to the top',
|
||||
toTop.scrollY === 0 && (await json("__gm.animation.valueAt('an-last')")) === null,
|
||||
JSON.stringify({ thumb, toTop }),
|
||||
);
|
||||
|
||||
await mutate(`
|
||||
const p = __gm.state.project;
|
||||
p.assets = p.assets.filter((a) => !['an-walk', 'an-box', 'an-sprite'].includes(a.id));
|
||||
|
||||
Reference in new issue
Block a user