fix: allow dragging all gates + stop waveform recording on edits
- INPUT/CLOCK gates can now be dragged (click-without-move = toggle, click-and-drag = move). Uses 4px movement threshold. - Waveform only records samples on intentional actions (INPUT toggle, manual step, simulation tick), not on gate placement/movement/connections. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
37
js/events.js
37
js/events.js
@@ -30,10 +30,20 @@ export function initEvents() {
|
||||
state.hoveredGate = state.hoveredPort ? state.hoveredPort.gate : findGateAt(world.x, world.y);
|
||||
|
||||
if (state.dragging) {
|
||||
// Detect if mouse actually moved (threshold of 4px to distinguish click vs drag)
|
||||
if (dragStartPos && !dragMoved) {
|
||||
const dx = e.offsetX - dragStartPos.x;
|
||||
const dy = e.offsetY - dragStartPos.y;
|
||||
if (Math.abs(dx) > 4 || Math.abs(dy) > 4) {
|
||||
dragMoved = true;
|
||||
}
|
||||
}
|
||||
if (dragMoved) {
|
||||
state.dragging.x = world.x - state.dragOffset.x;
|
||||
state.dragging.y = world.y - state.dragOffset.y;
|
||||
evaluateAll();
|
||||
}
|
||||
}
|
||||
|
||||
canvas.style.cursor = state.placingGate ? 'crosshair'
|
||||
: state.hoveredPort ? 'pointer'
|
||||
@@ -41,9 +51,14 @@ export function initEvents() {
|
||||
: 'default';
|
||||
});
|
||||
|
||||
let dragStartPos = null;
|
||||
let dragMoved = false;
|
||||
|
||||
canvas.addEventListener('mousedown', e => {
|
||||
if (e.button !== 0) return;
|
||||
const world = screenToWorld(e.offsetX, e.offsetY);
|
||||
dragStartPos = { x: e.offsetX, y: e.offsetY };
|
||||
dragMoved = false;
|
||||
|
||||
// Placing a new gate
|
||||
if (state.placingGate) {
|
||||
@@ -81,15 +96,8 @@ export function initEvents() {
|
||||
|
||||
if (state.connecting) { state.connecting = null; return; }
|
||||
|
||||
// Toggle INPUT/CLOCK
|
||||
// Drag any gate (including INPUT/CLOCK)
|
||||
const gate = findGateAt(world.x, world.y);
|
||||
if (gate && (gate.type === 'INPUT' || gate.type === 'CLOCK')) {
|
||||
gate.value = gate.value ? 0 : 1;
|
||||
evaluateAll();
|
||||
return;
|
||||
}
|
||||
|
||||
// Drag gate
|
||||
if (gate) {
|
||||
state.dragging = gate;
|
||||
state.dragOffset = { x: world.x - gate.x, y: world.y - gate.y };
|
||||
@@ -97,7 +105,18 @@ export function initEvents() {
|
||||
}
|
||||
});
|
||||
|
||||
canvas.addEventListener('mouseup', () => { state.dragging = null; });
|
||||
canvas.addEventListener('mouseup', e => {
|
||||
// Toggle INPUT/CLOCK only on click (no drag movement)
|
||||
if (state.dragging && !dragMoved) {
|
||||
const gate = state.dragging;
|
||||
if (gate.type === 'INPUT' || gate.type === 'CLOCK') {
|
||||
gate.value = gate.value ? 0 : 1;
|
||||
evaluateAll(true); // record waveform on intentional toggle
|
||||
}
|
||||
}
|
||||
state.dragging = null;
|
||||
dragStartPos = null;
|
||||
});
|
||||
|
||||
canvas.addEventListener('contextmenu', e => {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -53,12 +53,12 @@ export function evaluate(gate, visited = new Set()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function evaluateAll() {
|
||||
export function evaluateAll(recordWave = false) {
|
||||
state.gates.forEach(g => {
|
||||
if (g.type !== 'INPUT' && g.type !== 'CLOCK') g.value = 0;
|
||||
});
|
||||
state.gates.forEach(g => evaluate(g));
|
||||
if (state.recording && state.waveformVisible) recordSample();
|
||||
if (recordWave && state.recording && state.waveformVisible) recordSample();
|
||||
}
|
||||
|
||||
// Register evaluateAll in waveform to break circular dependency
|
||||
|
||||
Reference in New Issue
Block a user