mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-19 03:33:48 +00:00
ifcviewer: marquee box-select on web + suppress the canvas context menu
Bring rubber-band box-select to the web on the Web preset's select button (RMB). - Core: factor the pick-pass encode + rect copy out of picksInRect into encodeBoxPickToStaging (mirroring how single-pick shares encodePickReadbackToStaging), shared by the sync picksInRect (desktop) and a new async picksInRectAsync (web) — the latter maps the staging buffer via a spontaneous callback because the sync spin-map hangs the JS loop. New applyMarqueeToSelection (plain replace / Shift add / Ctrl remove). - Web main_web: a select-button drag past the click threshold draws a marquee rubber-band (a plain DOM <div> positioned in CSS px — no GPU overlay pass, which the web lib lacks) and on release box-picks the rect (device px) and applies it to the selection. A click (no drag) still single-picks. - Web shell.html: the #marquee div + styling, and — the reported bug — a contextmenu preventDefault on the canvas so RMB (now the select button) doesn't pop the browser menu. (Firefox still forces its native menu on Shift+RightClick; that's a browser escape hatch pages can't override.) Tests: applyMarqueeToSelection replace/add/remove + id-0 (Catch2, 124 total); web smoke marquee drag → rubber-band shown → selection changes → hidden (10/10). Desktop picksInRect unchanged in behaviour; BonsaiViewer builds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -343,3 +343,32 @@ test('hide selected removes geometry after a pick', async ({ page }) => {
|
||||
await page.waitForTimeout(400);
|
||||
expect(gpuErrors, gpuErrors.join('\n')).toEqual([]);
|
||||
});
|
||||
|
||||
test('RMB marquee drag box-selects (Web preset)', async ({ page }) => {
|
||||
const gpuErrors = [];
|
||||
page.on('console', (m) => { if (/Uncaptured WebGPU error|is invalid/i.test(m.text())) gpuErrors.push(m.text()); });
|
||||
await ready(page);
|
||||
|
||||
const box = await page.locator('#viewer-canvas').boundingBox();
|
||||
const cx = box.x + box.width / 2, cy = box.y + box.height / 2;
|
||||
const before = await shot(page);
|
||||
await page.mouse.move(cx - 120, cy - 90);
|
||||
await page.mouse.down({ button: 'right' });
|
||||
await page.mouse.move(cx - 40, cy - 30, { steps: 4 });
|
||||
const midDragVisible = await page.evaluate(() => {
|
||||
const m = document.getElementById('marquee');
|
||||
return !!(m && getComputedStyle(m).display !== 'none');
|
||||
});
|
||||
await page.mouse.move(cx + 120, cy + 90, { steps: 6 });
|
||||
await page.mouse.up({ button: 'right' });
|
||||
await page.waitForTimeout(600); // async box-pick + apply + render
|
||||
const after = await shot(page);
|
||||
const hiddenAfter = await page.evaluate(() => {
|
||||
const m = document.getElementById('marquee');
|
||||
return !!(m && getComputedStyle(m).display === 'none');
|
||||
});
|
||||
expect(midDragVisible, 'marquee rubber-band was not shown during the drag').toBe(true);
|
||||
expect(Buffer.compare(before, after), 'box-select did not change the canvas').not.toBe(0);
|
||||
expect(hiddenAfter, 'marquee was not hidden after release').toBe(true);
|
||||
expect(gpuErrors, gpuErrors.join('\n')).toEqual([]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user