Let a drag change only the picked clip in the Sound and Video tab (#403)
game-maker / gate (push) Successful in 4m15s
game-maker / suite (push) Failing after 15m40s

A drag with a clip picked could span a new clip in the strip or span
the picked one anew over the wave. Both happened by accident while
working on a clip. Now a drag only makes a new clip while none is
picked. With one picked it moves its edges or the whole of it.

- With no clip picked, a drag in the strip or over the wave (in the
  Video tab the track) spans a new clip, as before.
- A click over the wave or in the track picks the clip at that point,
  as a click on its band does. Beside the clips it picks the sound or
  the video. The picked clip wins where clips lie over each other.
- With a clip picked, its handles move its edges as before. A drag on
  its band in the strip moves the whole clip, its length kept and
  inside the file. Any other drag does nothing.
- The rules live in waveView.ts (clipGrip, clipToPick, movedSpan) and
  both tabs use them. The cursor shows grab over the picked band.
- The Video tab's track draws the clips not picked faint, as the wave
  does, so a click there has something to aim at.

Tests:
- Unit wave-view.test.ts: 16 tests (4 new)
- Counter-check: a strip drag beside the picked clip spanning a new
  one again fails the picked-clip rule test
- e2e 34 + 66 (atx): ALL PASSED, 162 checks, 1 new check in each
- Gate (atx): 295 files, 4527 tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-11 12:51:46 +02:00
1 parent c815d2c35f
commit ce933a4f32
7 files changed
+249 -68

No files matched your search

+41
View File
@@ -5,6 +5,8 @@
import { describe, expect, it } from 'vitest';
import {
clampWave,
clipGrip,
clipToPick,
coversShown,
draggedSpan,
drawnSeconds,
@@ -14,6 +16,7 @@ import {
levelMarks,
MAX_LEVEL,
MIN_LEVEL,
movedSpan,
rulerLabel,
rulerStep,
secondsToX,
@@ -138,6 +141,44 @@ describe('the cut span', () => {
});
});
describe('what a press over the clips does (#403)', () => {
const view = { panX: 0, pxPerSecond: 100 };
const picked = { start: 1, end: 2 };
it('spans a new clip anywhere while none is picked', () => {
expect(clipGrip(view, null, true, 150)).toBe('new');
expect(clipGrip(view, null, false, 250)).toBe('new');
});
it('with one picked, takes an edge over the wave and the whole clip on its band, nothing else', () => {
expect(clipGrip(view, picked, false, 101)).toBe('start');
expect(clipGrip(view, picked, false, 199)).toBe('end');
expect(clipGrip(view, picked, false, 150)).toBeNull();
expect(clipGrip(view, picked, false, 250)).toBeNull();
expect(clipGrip(view, picked, true, 150)).toBe('whole');
expect(clipGrip(view, picked, true, 101)).toBe('whole');
expect(clipGrip(view, picked, true, 250)).toBeNull();
});
it('picks the picked clip where it lies, else the band drawn last, else nothing', () => {
const bands = [
{ id: 'a', span: { start: 0, end: 1.5 } },
{ id: 'b', span: { start: 1, end: 3 } },
];
expect(clipToPick(view, bands, null, 120)).toBe('b');
expect(clipToPick(view, bands, 'a', 120)).toBe('a');
expect(clipToPick(view, bands, 'a', 200)).toBe('b');
expect(clipToPick(view, bands, 'b', 50)).toBe('a');
expect(clipToPick(view, bands, 'b', 350)).toBeNull();
});
it('moves a clip whole, its length kept and inside the file', () => {
expect(movedSpan(picked, 0.5, 3)).toEqual({ start: 1.5, end: 2.5 });
expect(movedSpan(picked, 5, 3)).toEqual({ start: 2, end: 3 });
expect(movedSpan(picked, -5, 3)).toEqual({ start: 0, end: 1 });
});
});
describe('the wave peaks', () => {
it('reads the lowest and highest sample of any stretch, over the blocks and the samples at its ends', () => {
const left = new Float32Array(1000);