Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 117 additions & 7 deletions tests/browser/interaction.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,18 +255,128 @@ test('selecting the current net again keeps the walked nets highlighted (#38)',
const aPx = await countColor(page, 'F', PALETTE[0]);
expect(aPx).toBeGreaterThan(0);

// From the net list.
await selectNetFromList(page, b);
let s = await state(page);
// From the last breadcrumb. The net list takes the net off instead.
await page.locator('#breadcrumb-bar .breadcrumb-item').last().click();
await settle(page);
const s = await state(page);
expect(s.highlightedNetPath).toEqual([a, b]);
expect(await countColor(page, 'F', PALETTE[0])).toBeGreaterThanOrEqual(aPx * 0.9);
});

// From the last breadcrumb.
await page.locator('#breadcrumb-bar .breadcrumb-item').last().click();
test('clicking a highlighted net in the list again takes only that net off', async ({ page }) => {
await load(page);
const [a, b] = frontNets;
await selectNetFromList(page, a);
await selectNetFromList(page, b);

// An earlier net: the current net and its pane stay.
await selectNetFromList(page, a);
let s = await state(page);
expect(s.highlightedNetPath).toEqual([b]);
expect(s.selectedNet).toBe(b);
expect(await countColor(page, 'F', PALETTE[0], 200)).toBe(0);
expect(await countColor(page, 'F', PALETTE[1])).toBeGreaterThan(0);

// The current net: back to the search list with nothing highlighted.
await selectNetFromList(page, b);
s = await state(page);
expect(s.highlightedNetPath).toEqual([]);
expect(s.selectedNet).toBeNull();
expect(s.highlightedNet).toBeNull();
await expect(page.locator('#net-search-panel')).toBeVisible();
expect(await countColor(page, 'F', PALETTE[1], 200)).toBe(0);
});

test('taking a net off the middle of A › B › A leaves one A', async ({ page }) => {
await load(page);
const [a, b] = frontNets;
await selectNetFromList(page, a);
await selectNetFromList(page, b);
await page.locator('#breadcrumb-bar .breadcrumb-item').first().click();
await settle(page);
expect((await state(page)).highlightedNetPath).toEqual([a, b, a]);

await selectNetFromList(page, b);
expect((await state(page)).highlightedNetPath).toEqual([a]);
});

// A spot on the front canvas, relative to its top left, where a click hits
// what match() accepts.
async function canvasSpot(page, match) {
const spot = await page.evaluate((src) => {
const match = eval(src);
const ld = allcanvas.front;
const div = document.getElementById('frontcanvas');
for (let gy = 1; gy < 40; gy++) {
for (let gx = 1; gx < 40; gx++) {
const e = { offsetX: div.clientWidth * gx / 40, offsetY: div.clientHeight * gy / 40 };
const hit = canvasHitScan('F', ...canvasToBoard(e, ld));
if (hit && match(hit)) return { x: e.offsetX, y: e.offsetY, hit };
}
}
return null;
}, match.toString());
expect(spot).not.toBeNull();
return spot;
}

async function clickCanvas(page, spot) {
const box = await page.locator('#frontcanvas').boundingBox();
await page.mouse.click(box.x + spot.x, box.y + spot.y);
await settle(page);
}

test('clicking a highlighted net on the board again takes it off', async ({ page }) => {
await load(page);
await page.keyboard.press('f');
await waitIdle(page);
const spot = await canvasSpot(page, (hit) => 'net' in hit && hit.net);

await clickCanvas(page, spot);
let s = await state(page);
expect(s.selectedNet).toBe(spot.hit.net);
expect(s.highlightedNetPath).toEqual([spot.hit.net]);

await clickCanvas(page, spot);
s = await state(page);
expect(s.highlightedNetPath).toEqual([a, b]);
expect(await countColor(page, 'F', PALETTE[0])).toBeGreaterThanOrEqual(aPx * 0.9);
expect(s.selectedNet).toBeNull();
expect(s.highlightedNetPath).toEqual([]);
});

test('clicking a part on the board again unpins and deselects it', async ({ page }) => {
await load(page);
await page.keyboard.press('f');
await waitIdle(page);
const spot = await canvasSpot(page, (hit) => 'footprint' in hit);
const idx = spot.hit.footprint;

await clickCanvas(page, spot);
let s = await state(page);
expect(s.selectedFootprintIdx).toBe(idx);
await expect(page.locator('#detail-pane')).toBeVisible();

await clickCanvas(page, spot);
s = await state(page);
expect(s.selectedFootprintIdx).toBeNull();
expect(await page.evaluate((i) => !!pinnedComponents[i], idx)).toBe(false);
await expect(page.locator('#detail-pane')).toBeHidden();
});

test('clicking a part row again unpins and deselects it', async ({ page }) => {
await load(page);
const idx = footprints.findIndex((fp) => fp.layer === 'F');
await page.locator('#tab-components').click();
const row = page.locator(`#comp-tbody .comp-row[data-idx="${idx}"]`);

await row.click();
await settle(page);
expect((await state(page)).selectedFootprintIdx).toBe(idx);

await row.click();
await settle(page);
expect((await state(page)).selectedFootprintIdx).toBeNull();
await expect(row).not.toHaveClass(/selected/);
await expect(page.locator('#detail-pane')).toBeHidden();
});

// #1: the nets stayed in the breadcrumbs, but the canvas showed only the
Expand Down
46 changes: 44 additions & 2 deletions web/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,8 @@ function populateComponentList() {
var idx = parseInt(this.dataset.idx);
hoverClear(); // the pin shows the part from here on
togglePinComponent(idx);
selectFootprint(idx, true);
if (pinnedComponents[idx]) selectFootprint(idx, true);
else deselectFootprint(idx);
});
tr.addEventListener("mouseenter", (function(idx) {
return function() { hoverFootprint(idx); };
Expand Down Expand Up @@ -755,7 +756,8 @@ function populateNetSearchList() {

row.addEventListener("click", function() {
hoverClear();
selectNet(netName);
if (netIsHighlighted(netName)) deselectNet(netName);
else selectNet(netName);
});
row.addEventListener("mouseenter", (function(n) {
return function() { hoverNet(n); };
Expand Down Expand Up @@ -956,6 +958,11 @@ function populateNetResults(netName) {
row.addEventListener("click", function(e) {
hoverClear();
togglePinComponent(fpIdx);
if (!pinnedComponents[fpIdx]) {
renderDetailPane(null, false);
deselectFootprint(fpIdx);
return;
}
renderDetailPane(fpIdx, false);
updateCompListSelection(fpIdx);
redrawAllIfDone();
Expand Down Expand Up @@ -1052,6 +1059,15 @@ function selectFootprint(fpIdx, zoomTo) {
}
}

// A part clicked again after its pin came off is no longer the selected part.
function deselectFootprint(fpIdx) {
if (selectedFootprintIdx !== fpIdx) return;
selectedFootprintIdx = null;
renderDetailPane(null);
updateCompListSelection(null);
updateHashFromSelection();
}

function updateCompListSelection(fpIdx) {
document.querySelectorAll(".comp-row").forEach(function(row) {
row.classList.toggle("selected", parseInt(row.dataset.idx) === fpIdx);
Expand Down Expand Up @@ -1274,6 +1290,30 @@ function clearWalkHistory() {
redrawAllIfDone();
}

function netIsHighlighted(netName) {
return netName === highlightedNet || highlightedNetPath.indexOf(netName) >= 0;
}

// Take one net off: its walk steps and colour, and the net pane if it is the
// current net. The other nets and parts stay as they are.
function deselectNet(netName) {
// Drop its steps, and a step that now repeats the one before it, as
// pushWalkStep never adds one: A › B › A without B is A.
netWalkHistory = netWalkHistory.filter(function(s) {
return !(s.type === "net" && s.value === netName);
}).filter(function(s, i, h) {
return i === 0 || h[i - 1].type !== s.type || h[i - 1].value !== s.value;
});
unregisterSelection('net', netName);
if (selectedNet === netName) {
selectedNet = null;
highlightedNet = null;
netGoBack();
}
rebuildBreadcrumbs();
updateHashFromSelection();
}

function deselect() {
selectedFootprintIdx = null;
selectedNet = null;
Expand Down Expand Up @@ -1335,13 +1375,15 @@ function initDetailResize() {
// ---- Canvas click callbacks (called from render.js) ----

function onNetClickedFromCanvas(netName) {
if (netIsHighlighted(netName)) { deselectNet(netName); return; }
document.getElementById("net-search-input").value = netName;
selectNet(netName);
switchTab("nets");
}

function onFootprintClickedFromCanvas(fpIdx) {
togglePinComponent(fpIdx);
if (!pinnedComponents[fpIdx]) { deselectFootprint(fpIdx); return; }
selectFootprint(fpIdx, false);
// Switch to components tab to show the selection
switchTab("components");
Expand Down
Loading