refactor: bus now spawns two paired terminals with a bus cable
Instead of a single pass-through gate, shift+drag now creates two BUS terminals (IN and OUT) connected by a thick bus cable. Internal connections between terminals are hidden and rendered as a single cable with /N notation and a diagonal slash. Each terminal is a thin cyan bar that can be moved independently. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import { GATE_W, GATE_H, COMP_W, PORT_R, GATE_COLORS } from './constants.js';
|
||||
import { state } from './state.js';
|
||||
import { getInputPorts, getOutputPorts, getComponentWidth, getComponentHeight } from './gates.js';
|
||||
import { getGateLabel, drawWaveLabels, drawWaveforms } from './waveform.js';
|
||||
import { isBusInternalConnection, getBusPairs } from './bus.js';
|
||||
|
||||
let canvas, ctx;
|
||||
|
||||
@@ -157,12 +158,13 @@ function drawBusGate(gate) {
|
||||
ctx.lineTo(gate.x + w / 2, gate.y + h - 6);
|
||||
ctx.stroke();
|
||||
|
||||
// Bus size label
|
||||
// Bus size label + role indicator
|
||||
ctx.font = 'bold 9px monospace';
|
||||
ctx.fillStyle = color;
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText(`${n}`, gate.x + w / 2, gate.y + h + 10);
|
||||
const roleIcon = gate.busRole === 'in' ? '▶' : gate.busRole === 'out' ? '◀' : '';
|
||||
ctx.fillText(`${roleIcon} ${n}`, gate.x + w / 2, gate.y + h + 10);
|
||||
|
||||
// Input ports (left)
|
||||
getInputPorts(gate).forEach(p => {
|
||||
@@ -200,6 +202,62 @@ function drawBusGate(gate) {
|
||||
});
|
||||
}
|
||||
|
||||
function drawBusCables() {
|
||||
const pairs = getBusPairs();
|
||||
for (const { inGate, outGate } of pairs) {
|
||||
const inW = getComponentWidth(inGate);
|
||||
const inH = getComponentHeight(inGate);
|
||||
const outH = getComponentHeight(outGate);
|
||||
|
||||
// Cable runs from right edge of inGate to left edge of outGate
|
||||
const x1 = inGate.x + inW;
|
||||
const y1 = inGate.y + inH / 2;
|
||||
const x2 = outGate.x;
|
||||
const y2 = outGate.y + outH / 2;
|
||||
|
||||
// Check if any channel is active
|
||||
const hasActive = inGate.outputValues?.some(v => v === 1);
|
||||
const n = parseInt(inGate.type.substring(4)) || 1;
|
||||
|
||||
// Outer thick cable (bus background)
|
||||
const cableWidth = Math.max(6, n * 2.5);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x1, y1);
|
||||
const midX = (x1 + x2) / 2;
|
||||
ctx.bezierCurveTo(midX, y1, midX, y2, x2, y2);
|
||||
ctx.strokeStyle = hasActive ? '#44ddff33' : '#44ddff11';
|
||||
ctx.lineWidth = cableWidth + 4;
|
||||
ctx.stroke();
|
||||
|
||||
// Inner cable
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x1, y1);
|
||||
ctx.bezierCurveTo(midX, y1, midX, y2, x2, y2);
|
||||
ctx.strokeStyle = hasActive ? '#44ddff' : '#44ddff66';
|
||||
ctx.lineWidth = cableWidth;
|
||||
ctx.stroke();
|
||||
|
||||
// Channel count label at midpoint
|
||||
const labelX = (x1 + x2) / 2;
|
||||
const labelY = (y1 + y2) / 2 - cableWidth / 2 - 6;
|
||||
ctx.font = 'bold 10px monospace';
|
||||
ctx.fillStyle = '#44ddff';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText(`/${n}`, labelX, labelY);
|
||||
|
||||
// Draw small diagonal slash across cable (bus notation)
|
||||
const slashX = labelX;
|
||||
const slashY = (y1 + y2) / 2;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(slashX - 6, slashY + 6);
|
||||
ctx.lineTo(slashX + 6, slashY - 6);
|
||||
ctx.strokeStyle = '#44ddff';
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
function drawComponentGate(gate) {
|
||||
const isHovered = state.hoveredGate === gate;
|
||||
const isActive = gate.value === 1;
|
||||
@@ -309,6 +367,9 @@ function drawComponentGate(gate) {
|
||||
}
|
||||
|
||||
function drawConnection(conn) {
|
||||
// Skip internal bus connections (rendered as bus cable instead)
|
||||
if (isBusInternalConnection(conn)) return;
|
||||
|
||||
const fromGate = state.gates.find(g => g.id === conn.from);
|
||||
const toGate = state.gates.find(g => g.id === conn.to);
|
||||
if (!fromGate || !toGate) return;
|
||||
@@ -507,6 +568,7 @@ function draw() {
|
||||
|
||||
drawGrid();
|
||||
state.connections.forEach(drawConnection);
|
||||
drawBusCables();
|
||||
state.gates.forEach(drawGate);
|
||||
drawConnectingWire();
|
||||
drawBusCutLine();
|
||||
|
||||
Reference in New Issue
Block a user