/** * @param {!Painter} painter * @param {!CircuitStats} stats * @param {!Hand} hand */ paint(painter, stats, hand) { painter.fillRect(this.area, Config.BACKGROUND_COLOR_TOOLBOX); for (let groupIndex = 0; groupIndex < Gates.Sets.length; groupIndex++) { let group = Gates.Sets[groupIndex]; painter.printLine(group.hint, this.groupLabelRect(groupIndex), 0.5, 'black', 16); for (let gateIndex = 0; gateIndex < group.gates.length; gateIndex++) { let gate = group.gates[gateIndex]; if (gate !== null) { let rect = this.gateDrawRect(groupIndex, gateIndex); let isHighlighted = seq(hand.hoverPoints()).any(pt => rect.containsPoint(pt)); let drawer = gate.customDrawer || GatePainting.DEFAULT_DRAWER; painter.noteTouchBlocker({rect, cursor: 'pointer'}); drawer(new GateDrawParams( painter, true, isHighlighted, false, false, rect, Util.notNull(gate), stats, null, [], undefined)); } } } // Draw tooltip when hovering, but also when dragging a gate over its own toolbox spot. let f = this.findGateAt(hand.pos); if (f !== null && (hand.heldGate === undefined || f.gate.symbol === hand.heldGate.symbol)) { let gateRect = this.gateDrawRect(f.groupIndex, f.gateIndex); let hintRect = new Rect(gateRect.right() + 1, gateRect.center().y, 500, 200). snapInside(painter.paintableArea().skipTop(gateRect.y)); painter.defer(() => WidgetPainter.paintGateTooltip(painter, hintRect, f.gate, stats.time)); } let r = new Rect(0, 0, Config.TOOLBOX_MARGIN_X, this.area.h); let {x, y} = r.center(); painter.ctx.save(); painter.ctx.translate(x, y); painter.ctx.rotate(-Math.PI/2); painter.printLine("Toolbox", new Rect(-r.h / 2, -r.w / 2, r.h, r.w), 0.5, 'black', 24); painter.ctx.restore(); }
/** * @param {!InspectorWidget|*} other * @returns {!boolean} */ isEqualTo(other) { if (this === other) { return true; } //noinspection JSUnresolvedVariable return other instanceof InspectorWidget && this.drawArea.isEqualTo(other.drawArea) && this.displayedCircuit.isEqualTo(other.displayedCircuit) && this.toolboxWidget.isEqualTo(other.toolboxWidget) && this.hand.isEqualTo(other.hand); }
).withCustomDrawer(args => { if (args.isInToolbox || args.isHighlighted) { GatePainting.DEFAULT_DRAWER(args); return; } // A swap gate half is shown as a small X (joined by a line to the other half; that's handled elsewhere). let swapRect = Rect.centeredSquareWithRadius(args.rect.center(), args.rect.w / 6); args.painter.strokeLine(swapRect.topLeft(), swapRect.bottomRight()); args.painter.strokeLine(swapRect.topRight(), swapRect.bottomLeft()); })
/** * @param {!Painter} painter * @param {!CircuitStats} stats * @param {!boolean} shift */ paint(painter, stats, shift) { painter.fillRect(this.drawArea, Config.BACKGROUND_COLOR); this.toolboxWidget.paint(painter, stats, this.hand); this.displayedCircuit.paint(painter, this.hand, stats, shift); this._paintHand(painter, stats); this._drawHint(painter); // When a gate is being dragged off the bottom, this fades it out instead of clipping it. let y1 = this.displayedCircuit.top + DisplayedCircuit.desiredHeight(this.displayedCircuit.circuitDefinition.numWires); let y2 = this.drawArea.bottom(); var gradient = painter.ctx.createLinearGradient(0, y1, 0, y2); gradient.addColorStop(0, 'rgba(255,255,255,0)'); gradient.addColorStop(1, 'white'); painter.ctx.fillStyle = gradient; painter.ctx.fillRect(0, y1, this.drawArea.w, y2-y1); }
/** * Draws a peek gate on each wire at the right-hand side of the circuit. * * @param {!Painter} painter * @param {!CircuitStats} stats * @param {!int} col * @param {!Hand} hand * @private */ _drawOutputSuperpositionDisplay(painter, stats, col, hand) { let numWire = this.importantWireCount(); if (numWire >= Config.NO_SUPERPOSITION_DRAWING_WIRE_THRESHOLD) { return; } let [colWires, rowWires] = [Math.floor(numWire/2), Math.ceil(numWire/2)]; let [colCount, rowCount] = [1 << colWires, 1 << rowWires]; let outputStateBuffer = stats.finalState.rawBuffer(); if (stats.circuitDefinition.numWires !== this.importantWireCount()) { outputStateBuffer = outputStateBuffer.slice(0, outputStateBuffer.length/2); } let amplitudeGrid = new Matrix(colCount, rowCount, outputStateBuffer); let topRect = this.gateRect(0, col); let bottomRect = this.gateRect(numWire-1, col); let gridRect = new Rect(topRect.x, topRect.y, 0, bottomRect.bottom() - topRect.y); gridRect = gridRect.withW(gridRect.h * (colCount/rowCount)); MathPainter.paintMatrix( painter, amplitudeGrid, gridRect, numWire < Config.SIMPLE_SUPERPOSITION_DRAWING_WIRE_THRESHOLD ? Config.SUPERPOSITION_MID_COLOR : undefined, 'black', numWire < Config.SIMPLE_SUPERPOSITION_DRAWING_WIRE_THRESHOLD ? Config.SUPERPOSITION_FORE_COLOR : undefined, Config.SUPERPOSITION_BACK_COLOR, hand.hoverPoints()); let expandedRect = gridRect.withW(gridRect.w + 50).withH(gridRect.h + 50); let [dw, dh] = [gridRect.w / colCount, gridRect.h / rowCount]; // Row labels. for (let i = 0; i < rowCount; i++) { let label = "_".repeat(colWires) + Util.bin(i, rowWires); let x = gridRect.right(); let y = expandedRect.y + dh*(i+0.5); painter.print(label, x + 2, y, 'left', 'middle', 'black', '12px monospace', 50, dh, (w, h) => { painter.fillRect(new Rect(x, y-h/2, w + 4, h), 'lightgray'); }); } // Column labels. painter.ctx.save(); painter.ctx.rotate(Math.PI/2); let maxY = 0; for (let i = 0; i < colCount; i++) { let labelRect = expandedRect.skipTop(gridRect.h + 2).skipLeft(dw*i).skipBottom(2).withW(dw); labelRect = new Rect(labelRect.y, -labelRect.x-labelRect.w, labelRect.h, labelRect.w); let label = Util.bin(i, colWires) + "_".repeat(rowWires); let x = expandedRect.x + dw*(i+0.5); let y = gridRect.bottom(); painter.print(label, y + 2, -x, 'left', 'middle', 'black', '12px monospace', 50, dw, (w, h) => { painter.fillRect(new Rect(y, -x-h/2, w + 4, h), 'lightgray'); maxY = Math.max(maxY, w + 8); }); } painter.ctx.restore(); // Hint text. painter.printParagraph( "Final amplitudes\n(deferring measurement)", expandedRect.withY(gridRect.bottom() + maxY).withH(40).withW(200), new Point(0, 0), 'gray'); }